android AppWidget中添加自定义View

来源:互联网 发布:pc蛋蛋单双算法 编辑:程序博客网 时间:2024/05/20 06:56

最近接了个任务,在小部件(AppWidget)中播放动画。android中小部件是使用RemoteViews加载布局。但RemoteViews支持的View很少,并且不支持自定义View。

如果让RemoteViews支持自定义View,需要在将该View放到framewoke下编译。现记录实现过程如下:

1.自定义View,将class文件放到\frameworks\base\core\java\android\widget/目录下,并在代码第一行添加@RemoteViews.RemoteView标签。代码如下:

自定义的RobotAnimView是一个动画类,主要增加播放动画方法。

package android.widget;import android.R;import android.animation.ValueAnimator;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.ColorFilter;import android.graphics.Matrix;import android.graphics.PixelFormat;import android.graphics.PointF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;import android.view.animation.Interpolator;import android.view.animation.LinearInterpolator;import android.widget.RemoteViews;@RemoteViews.RemoteViewpublic class RobotAnimView extends View {    private WaveRobotAnimator mAnimator;    public RobotAnimView(Context context) {        super(context);        init();    }    public RobotAnimView(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    public RobotAnimView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init();    }    public void startRobotAnimator(boolean start) {        if (start) {            startRobotAnimator();        } else {            endRobotAnimator();        }    }    public void startRobotAnimator() {        init();        mAnimator.start();    }    public void endRobotAnimator() {        if (mAnimator != null) {            if (mAnimator.isRunning()) {                mAnimator.end();            }            mAnimator = null;        }    }    private void init() {        endRobotAnimator();        mAnimator = new WaveRobotAnimator(getContext(), false);        this.setBackground(mAnimator.getDrawable());    }    private class WaveRobotAnimator extends ValueAnimator implements ValueAnimator.AnimatorUpdateListener {        private RobotDrawable mDrawable;        WaveRobotAnimator(Context context, boolean left) {            this.setDuration(1700);            this.setIntValues(0, 1700);            this.setInterpolator(new LinearInterpolator());            mDrawable = new RobotDrawable(context, left);            addUpdateListener(this);        }        @Override        public void onAnimationUpdate(ValueAnimator animation) {            mDrawable.update((int) (animation.getAnimatedValue()));            mDrawable.invalidateSelf();        }        Drawable getDrawable() {            return mDrawable;        }        private class RobotDrawable extends Drawable {            private int mTime;            private Body mBody;            private EyeLeft mEyeLeft;            private EyeRight mEyeRight;            private HandLeft mHandLeft;            private HandRight mHandRight;            private Head mHead;            private Mouth mMouth;            private int mWidth;            private int mHeight;            private boolean mIsLeft;            RobotDrawable(Context context, boolean left) {                mIsLeft = left;                mBody = new Body(context);                mEyeLeft = new EyeLeft(context);                mEyeRight = new EyeRight(context);                mHandLeft = new HandLeft(context);                mHandRight = new HandRight(context);                mHead = new Head(context);                mMouth = new Mouth(context);            }            @Override            public void setAlpha(int alpha) {            }            private void update(int time) {                mTime = time;            }            @Override            public void draw(Canvas canvas) {                if (mWidth == 0 || mHeight == 0) {                    mWidth = canvas.getWidth();                    mHeight = canvas.getHeight();                }                canvas.save();                if (mIsLeft) {                    canvas.scale(-1, 1, canvas.getWidth() / 2f, canvas.getHeight() / 2f);                }                canvas.translate(mWidth / 2f - 126 / 2, mHeight / 2f - 164 / 2);                float bodyProgress = mBody.getProgress(mTime);                canvas.rotate(bodyProgress, 63, 164);                canvas.save();                float headProgress = mHead.getProgress(mTime);                canvas.rotate(headProgress, 63, 103);                mHead.draw(canvas);                mEyeLeft.draw(canvas, mTime);                mEyeRight.draw(canvas, mTime);                mMouth.draw(canvas);                canvas.restore();                mBody.draw(canvas);                mHandLeft.draw(canvas, mTime);                mHandRight.draw(canvas, mTime);                canvas.restore();            }            @Override            public void setColorFilter(ColorFilter colorFilter) {            }            @Override            public int getOpacity() {                return PixelFormat.UNKNOWN;            }        }        private class Body extends Basic {            private final Interpolator[] mInterpolator = {                    new EaseCubicInterpolator(0.48f, 0.06f, 0.52f, 0.94f),                    new EaseCubicInterpolator(0.47f, 0.00f, 0.77f, 0.63f),                    new EaseCubicInterpolator(0.34f, -0.68f, 0.55f, -1.14f),                    new EaseCubicInterpolator(0.48f, 0.00f, 0.52f, 1.00f)            };            private final float[] mProgress = {0f, 18f, 17.7f, 18.0f};            Body(Context context) {                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_body);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 57, 59, true);            }            private void draw(Canvas canvas) {                mMatrix.setTranslate(34, 103);                canvas.drawBitmap(mBitmap, mMatrix, null);            }            float getProgress(int time) {                return getProgress(time, mTimes, mProgress, mInterpolator);            }        }        private class EyeLeft extends Eye {            EyeLeft(Context context) {                mTransX = 28;                mTransY = 57;                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_eye_left);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 18, 22, true);            }        }        private class EyeRight extends Eye {            EyeRight(Context context) {                mTransX = 80;                mTransY = 57;                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_eye_right);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 18, 22, true);            }        }        class Eye extends Basic {            final float[] mTimes = {50f, 200f};            final float[] mProgress = {1f, 0.15f, 1f};            final Interpolator[] mInterpolator = {                    new EaseCubicInterpolator(0.33f, 0.00f, 0.67f, 1.00f),                    new EaseCubicInterpolator(0.33f, 0.00f, 0.67f, 1.00f)            };            int mTransX;            int mTransY;            void draw(Canvas canvas, int time) {                mMatrix.setTranslate(mTransX, mTransY);                if (time >= 1000 && time <= 1250) {                    float scale = getProgress(time - 1000, mTimes, mProgress, mInterpolator);                    mMatrix.postScale(1, scale, mTransX + mBitmap.getWidth() / 2f, mTransY + mBitmap.getHeight() / 2f);                }                canvas.drawBitmap(mBitmap, mMatrix, null);            }        }        private class HandLeft extends Basic {            private final float[] mProgress = {0f, 116f, 80f, 116f};            private final Interpolator[] mInterpolator = {                    new EaseCubicInterpolator(0.44f, 0.20f, 0.71f, 1.00f),                    new EaseCubicInterpolator(0.48f, 0.00f, 0.44f, 1.00f),                    new EaseCubicInterpolator(0.53f, 0.00f, 0.61f, 1.00f),                    new EaseCubicInterpolator(0.17f, 0.00f, 0.52f, 1.00f)            };            HandLeft(Context context) {                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_hand_left);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 19, 27, true);            }            private void draw(Canvas canvas, int time) {                float progress = getProgress(time, mTimes, mProgress, mInterpolator);                mMatrix.setTranslate(16, 116);                mMatrix.postRotate(progress, 37, 114);                canvas.drawBitmap(mBitmap, mMatrix, null);            }        }        private class HandRight extends Basic {            private final float[] mProgress = {0f, -25f, -24.6f, -25f};            private final Interpolator[] mInterpolator = {                    new EaseCubicInterpolator(0.48f, 0.06f, 0.52f, 0.94f),                    new EaseCubicInterpolator(0.47f, 0.00f, 0.77f, 0.63f),                    new EaseCubicInterpolator(0.34f, -0.68f, 0.55f, -1.14f),                    new EaseCubicInterpolator(0.48f, 0.00f, 0.52f, 1.00f)            };            HandRight(Context context) {                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_hand_right);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 19, 27, true);            }            private void draw(Canvas canvas, int time) {                float progress = getProgress(time, mTimes, mProgress, mInterpolator);                mMatrix.setTranslate(90, 116);                mMatrix.postRotate(progress, 88, 114);                canvas.drawBitmap(mBitmap, mMatrix, null);            }        }        private class Head extends Basic {            private final float[] mProgress = {0f, 18f, 17.7f, 18f};            private final Interpolator[] mInterpolator = {                    new EaseCubicInterpolator(0.48f, 0.60f, 0.52f, 0.94f),                    new EaseCubicInterpolator(0.47f, 0.00f, 0.77f, 0.63f),                    new EaseCubicInterpolator(0.34f, -0.68f, 0.55f, -1.14f),                    new EaseCubicInterpolator(0.48f, 0.00f, 0.52f, 1.00f)            };            Head(Context context) {                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_head);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 126, 103, true);            }            private void draw(Canvas canvas) {                canvas.drawBitmap(mBitmap, mMatrix, null);            }            float getProgress(int time) {                return getProgress(time, mTimes, mProgress, mInterpolator);            }        }        private class Mouth extends Basic {            Mouth(Context context) {                mBitmap = BitmapFactory.decodeResource(context.getResources(), com.android.internal.R.drawable.anim_robot_mouth);                mBitmap = Bitmap.createScaledBitmap(mBitmap, 12, 8, true);            }            private void draw(Canvas canvas) {                mMatrix.setTranslate(57, 81);                canvas.drawBitmap(mBitmap, mMatrix, null);            }        }        private class Basic {            final float[] mTimes = {700f, 200f, 250f, 550f};            Bitmap mBitmap;            Matrix mMatrix = new Matrix();            float getProgress(int time, float[] times, float[] progresss, Interpolator[] interpolators) {                float progress = 0f;                float t;                if (time < times[0]) {                    t = 1f * time / times[0];                    progress = progresss[0] + interpolators[0].getInterpolation(t) * (progresss[1] - progresss[0]);                } else if (time < times[0] + times[1]) {                    t = 1f * (time - times[0]) / times[1];                    progress = progresss[1] + interpolators[1].getInterpolation(t) * (progresss[2] - progresss[1]);                } else if (time < times[0] + times[1] + times[2]) {                    t = 1f * (time - times[1] - times[0]) / times[2];                    progress = progresss[2] + interpolators[2].getInterpolation(t) * (progresss[3] - progresss[2]);                } else if (time < times[0] + times[1] + times[2] + times[3]) {                    t = 1f * (time - times[2] - times[1] - times[0]) / times[3];                    progress = progresss[3] + interpolators[3].getInterpolation(t) * (0 - progresss[3]);                }                return progress;            }        }    }    private class EaseCubicInterpolator implements Interpolator {        private final static int ACCURACY = 4096;        private static final float STEP_SIZE = 1.0f / ACCURACY;        private int mLastI = 0;        private final PointF mControlPoint1 = new PointF();        private final PointF mControlPoint2 = new PointF();        EaseCubicInterpolator(float x1, float y1, float x2, float y2) {            mControlPoint1.x = x1;            mControlPoint1.y = y1;            mControlPoint2.x = x2;            mControlPoint2.y = y2;        }        @Override        public float getInterpolation(float input) {            float t = input;            for (int i = mLastI; i < ACCURACY; i++) {                t = i * STEP_SIZE;                double x = cubicCurves(t, 0, mControlPoint1.x, mControlPoint2.x, 1);                if (x >= input) {                    mLastI = i;                    break;                }            }            double value = cubicCurves(t, 0, mControlPoint1.y, mControlPoint2.y, 1);            if (value == 1) {                mLastI = 0;            }            return (float) value;        }        double cubicCurves(double t, double value0, double value1, double value2, double value3) {            double value;            double u = 1 - t;            double tt = t * t;            double uu = u * u;            double uuu = uu * u;            double ttt = tt * t;            value = uuu * value0;            value += 3 * uu * t * value1;            value += 3 * u * tt * value2;            value += ttt * value3;            return value;        }    }}
二、自定义View中需要引入bitmap资源。使用R.drawable时,参考TextView源码,使用com.android.internal.R.drawable.形式引入。

三、png资源文件放到\frameworks\base\core\res\res\drawable\目录下。 

只将图片放到drawable目录下编译时编不过,会找不到图片资源。参考TextView源码,将用到的资源在frameworks/base/core/res/res/values/symbols.xml中声明。查资料得知,自己添加的资源要在public.xml(资源可对外使用)或symbols.xml(资源私有)中声明。

代码片段:

  <java-symbol type="drawable" name="anim_robot_body" />
  <java-symbol type="drawable" name="anim_robot_eye_left" />
  <java-symbol type="drawable" name="anim_robot_eye_right" />
  <java-symbol type="drawable" name="anim_robot_hand_left" />
  <java-symbol type="drawable" name="anim_robot_hand_right" />
  <java-symbol type="drawable" name="anim_robot_head" />
  <java-symbol type="drawable" name="anim_robot_mouth" />

四、编译framework代码,将生成的framework.jar和framew-res.apk push到手机中。Remoteview就可以使用自定义View了。小部件如何用RemoteView后面再更新。


原创粉丝点击