Android(安卓)AppWidget(桌面小部件-音乐播放动画)
16lz
2021-01-25
桌面小部件基础篇:Android AppWidget (桌面小部件)
音乐播放 (动画实现)
一个音乐播放的柱状图(不会上传动图,自行脑补)
思路方案:
1,自定义View,widget 仅支持部分控件,自定义没用,我把自定义弄完了,才想起来。所以这个方案pass
2,帧动画,直接使用ImageView,也不行,无法获取子控件属性,帧动画运行不了
3,LayoutAnimation,这个我还没试怎么实现复杂动画,不过应该可以实现简单的 缩放,透明度,等属性动画(自己测试吧)
4,线程实现帧动画
5,handler 实现帧动画(比较好控制)
自定义View(记录,不是最终选择方案)
package cn.sh.changxing.onlineradio.view;import android.animation.ValueAnimator;import android.annotation.TargetApi;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.os.Build;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.animation.LinearInterpolator;import android.widget.RemoteViews;import java.util.Random;/** * 仿柱形频谱 动画播放 */public class PlayerView extends View { private static final String TAG = "PlayerView2"; /** * 画笔 */ private Paint paint; /** * 整个控件宽,高,最终取值 */ private int width, height, min; /** * 小矩形边长 */ private float border; /** * 间隔 */ private float interval; /** * 柱状图 X*X(默认 7*7) */ private int line = 7; private ValueAnimator valueAnimator; private int current = -1; private int random = 0; public PlayerView(Context context) { this(context, null); } public PlayerView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public PlayerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 初始化 */ private void init() { Log.e(TAG, "init: "); paint = new Paint(); paint.setStyle(Paint.Style.FILL_AND_STROKE); paint.setColor(Color.WHITE); initAnimation(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (width == 0 || height == 0) { width = getMeasuredWidth(); height = getMeasuredHeight(); min = Math.min(width, height); interval = (float) (min * 0.025); border = (min - (line + 1) * interval) / line; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制 多列 for (int i = 0; i < line; i++) { drawColumnRect(canvas, (i + 1) * interval + i * border, random); } } /** * 绘制一列 * * @param canvas * @param startX X轴的起始位置 * @param random 为了动画效果,设置额外增加的随机数个数(每列生成个数 = 随机生成的个数+额外统一增加个数) 达到上下抖动效果 */ private void drawColumnRect(Canvas canvas, float startX, int random) { //随机生成个数 //根据 间隔,小方块边长,个数,确定要绘制的小方块区域 int size = new Random().nextInt(4);//0-3 for (int i = 0; i < random + size; i++) { RectF rectF = new RectF(); rectF.left = startX; rectF.top = min - (i + 1) * (border + interval); rectF.right = startX + border; rectF.bottom = min - (i + 1) * interval - i * border; //透明度变化 paint.setAlpha(50 + i * 30); canvas.drawRect(rectF, paint); } } /** * 开始播放 */ public void startPlay() { if (null != valueAnimator && !valueAnimator.isRunning()) { valueAnimator.start(); } else { initAnimation(); startPlay(); } } /** * 停止播放 */ @TargetApi(Build.VERSION_CODES.KITKAT) public void stop() { if (null != valueAnimator && valueAnimator.isRunning()) { valueAnimator.pause(); } } /** * 销毁 回收 */ public void destroy() { } /** * 初始化动画 (暂时写死) */ private void initAnimation() { valueAnimator = ValueAnimator.ofInt(0, 5); valueAnimator.setDuration(850); valueAnimator.setRepeatCount(ValueAnimator.INFINITE); valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { int progress = (int) animation.getAnimatedValue(); if (progress != current) { postInvalidate(); random = new Random().nextInt(5);//额外增加个数 0-4 current = progress; } } }); }}
一个随机生成小方块,也能做到类似音频播放时的效果,部分直接写死的参数,记录一下,并不能用在 Widget上。
Handler实现
package cn.sh.changxing.onlineradio.widget;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.graphics.Bitmap;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.util.Log;import android.widget.RemoteViews;import com.ximalaya.ting.android.opensdk.player.XmPlayerManager;import cn.sh.changxing.applib.constant.SysBroadcastConstant;import cn.sh.changxing.onlineradio.OnlineRadioApplication;import cn.sh.changxing.onlineradio.R;import cn.sh.changxing.onlineradio.activity.MainActivity;import cn.sh.changxing.onlineradio.service.aidl.IMediaPlayerService;import static cn.sh.changxing.applib.constant.SysBroadcastConstant.ACTION_NOTIFY_MPLAYER_STATE_CHANGED;import static cn.sh.changxing.applib.constant.SysBroadcastConstant.EXTRA_VALUE_NOTIFY_MPLAYER_PLAYING;public class RadioWidgetProvider2 extends AppWidgetProvider { private static final String TAG = "RadioWidgetProvider2"; public static int REQUEST_GO_ACTIVITY_CODE = 112; private static final int START_ANIMATION = 0; private static final int END_ANIMATION = 1; private static Context mContext; private static RemoteViews remoteViews; private IMediaPlayerService mediaPlayerService; private int[] bitmapId = new int[]{R.drawable.radio_play_gif_2, R.drawable.radio_play_gif_3, R.drawable.radio_play_gif_4, R.drawable.radio_play_gif_5, R.drawable.radio_play_gif_6, R.drawable.radio_play_gif_8, R.drawable.radio_play_gif_9, R.drawable.radio_play_gif_10, R.drawable.radio_play_gif_11, R.drawable.radio_play_gif_12, R.drawable.radio_play_gif_13, R.drawable.radio_play_gif_14, R.drawable.radio_play_gif_13, R.drawable.radio_play_gif_12, R.drawable.radio_play_gif_11, R.drawable.radio_play_gif_10, R.drawable.radio_play_gif_9, R.drawable.radio_play_gif_8, R.drawable.radio_play_gif_6, R.drawable.radio_play_gif_5, R.drawable.radio_play_gif_4, R.drawable.radio_play_gif_3}; //图片资源// private int[] bitmapId = new int[]{R.drawable.radio_play_gif_2, R.drawable.radio_play_gif_4, R.drawable.radio_play_gif_6, R.drawable.radio_play_gif_8,// R.drawable.radio_play_gif_10, R.drawable.radio_play_gif_12, R.drawable.radio_play_gif_14}; //动画间隔时间/ms private long sleep = 100; private static boolean isRun = false; @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); if (null == mContext) { mContext = context; } //设置默认初始显示图片 remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_radio); remoteViews.setImageViewResource(R.id.onlineRadio_widget, bitmapId[0]); //点击进入应用 startRadio(); //多个Widget的情况 刷新 for (int i = 0; i < appWidgetIds.length; i++) { Log.e(TAG, "onUpdate: "); appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews); } //初始播放状态 initStatus(); } /** * 获取 播放器状态 */ private void initStatus(){ OnlineRadioApplication application = OnlineRadioApplication.getInstance(); XmPlayerManager manager = XmPlayerManager.getInstance(application); if(manager.isPlaying()){ if(!isRun){ Log.e(TAG, "initStatus: isPlaying"); isRun = true; Message msg = mHandler.obtainMessage(START_ANIMATION); msg.arg1 = 0; mHandler.sendMessage(msg); } } } /** * 播放器状态发生变化 接收广播 * @param context * @param intent */ @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); Message msg = mHandler.obtainMessage(START_ANIMATION); msg.arg1 = 0; String action = intent.getAction(); if (action.equals(ACTION_NOTIFY_MPLAYER_STATE_CHANGED)) { String appPackName = intent.getStringExtra(SysBroadcastConstant.EXTRA_NAME_APP_PACKAGE); if (appPackName.equals(OnlineRadioApplication.getInstance().getPackageName())) { int state = intent.getIntExtra(SysBroadcastConstant.EXTRA_NAME_NOTIFY_MPLAYER_STATE, 1); switch (state) { case EXTRA_VALUE_NOTIFY_MPLAYER_PLAYING: if(!isRun){ isRun = true; mHandler.sendMessage(msg); Log.e(TAG, "onReceive: 播放"); } break; default: if(isRun){ isRun = false; mHandler.sendEmptyMessage(END_ANIMATION); Log.e(TAG, "onReceive: 暂停"); } break; } } else { int state = intent.getIntExtra(SysBroadcastConstant.EXTRA_NAME_NOTIFY_MPLAYER_STATE, 1); if (state == EXTRA_VALUE_NOTIFY_MPLAYER_PLAYING) { if(!isRun){ isRun = true; mHandler.sendMessage(msg); Log.e(TAG, "onReceive: 播放"); } } } } } private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); AppWidgetManager appWidgetManger = AppWidgetManager.getInstance(mContext); int[] appIds = appWidgetManger.getAppWidgetIds(new ComponentName(mContext, RadioWidgetProvider2.class)); if (msg.what == START_ANIMATION) { if (!isRun) { return; } if (null != remoteViews) { remoteViews.setImageViewResource(R.id.onlineRadio_widget, bitmapId[msg.arg1]); appWidgetManger.updateAppWidget(appIds, remoteViews); //循环切换 Message message = mHandler.obtainMessage(START_ANIMATION); message.arg1 = (msg.arg1 + 1) % bitmapId.length; mHandler.sendMessageDelayed(message, sleep); } } else if (msg.what == END_ANIMATION) { //停止时显示默认图片 remoteViews.setImageViewResource(R.id.onlineRadio_widget, bitmapId[0]); appWidgetManger.updateAppWidget(appIds, remoteViews); } } }; /*** * * 点击背景 进入radio * */ private void startRadio() { Intent intent = new Intent(mContext, MainActivity.class); intent.setAction("cn.sh.changxing.action.redio"); intent.addCategory("android.intent.category.DEFAULT"); PendingIntent pendingIntent = PendingIntent.getActivity(mContext, REQUEST_GO_ACTIVITY_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT); remoteViews.setOnClickPendingIntent(R.id.widget_layout, pendingIntent); } /*** * 检测电台服务是否开启 没有开启的话自动开启 * @param context */ public void startRadioService(final Context context) { mediaPlayerService = OnlineRadioApplication.getInstance().getMediaPlayerService(); if (mediaPlayerService == null) { Intent intent = new Intent(); intent.setAction("cn.sh.changxing.onlineradio.service.MediaPlayerServiceCTL"); context.bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "服务开启成功" + name); mediaPlayerService = IMediaPlayerService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "服务关闭" + name); context.unbindService(this); } }, Context.BIND_NOT_FOREGROUND); } } @Override public void onEnabled(Context context) { super.onEnabled(context); startRadioService(context); } @Override public void onDisabled(Context context) { super.onDisabled(context); System.gc(); }}
代码注释清晰,准备好图片数组,首先判断播放器状态,看是否启动动画。所有处理在handlerMessage中,判断是否播放,停止。
更多相关文章
- Android小项目之五 splash动画效果
- Android(安卓)UI开源组件库BottomView ,第三方自定义UI控件
- [Android]Fragment自定义动画、动画监听以及兼容性包使用
- Android简易的仿微信聊天的语音播放控件
- 如何实现Siri中的波纹动画
- 手把手教你绘制Android粘性果冻动画组件
- 一对一视频直播系统Android补间动画-雷达扫描效果
- Android(安卓)的属性动画的实现和使用详解
- androidのXlist框架上拉下拉刷新案例