自定义view和属性动画相关

上实现效果


3.gif

这个效果是通过两个布局,分别都有动画效果来进行实现的

public class PowerCoolLayout extends View {

    private Paint paint;
    private Bitmap bitmap;
    private int dp250;
    private int dp100;
    private Rect rect;
    private LinearGradient greenShader;
    private LinearGradient redShader;
    private Paint gradientPaint;

    private ValueAnimator valueAnimator;
    private Path snowPath;
    private Path snowPath2;
    private Path snowPath3;
    private PathMeasure pathMeasure;
    private PathMeasure pathMeasure2;
    private PathMeasure pathMeasure3;
    private float[] mCurrentPosition = new float[2];
    private float[] mCurrentPosition2 = new float[2];
    private float[] mCurrentPosition3 = new float[2];
    private Bitmap snowBitmap;
    private Bitmap snowBitmap2;
    private Rect bitmapRect2;
    private Rect desBitmapRect2;
    private Rect bitmapRect3;
    private Rect desBitmapRect3;

    //摄氏度的值
    private String drawCelsiusText;
    private double currentCelsius;

    public PowerCoolLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setTextSize(UiUtils.dp2px(getContext(), 40));

        gradientPaint = new Paint();

        bitmap = getBitmap(R.drawable.ic_report_mobile_cool, false);
        dp250 = UiUtils.dp2px(getContext(), 150);
        dp100 = UiUtils.dp2px(getContext(), 100);

        snowPath = new Path();
        snowPath2 = new Path();
        snowPath3 = new Path();

        snowBitmap = getBitmap(R.drawable.ic_snow, false);
        snowBitmap2 = getBitmap(R.drawable.ic_snow, true);


        drawCelsiusText = String.valueOf(MyApplication.PHONE_CELSIUS) + "°";
        currentCelsius = getRandomCool();
    }

    /**
     * 来回降5度多一点
     *
     * @return
     */
    private double getRandomCool() {
        return (((int) (new Random().nextDouble() * 100)) / 100.0 + 9);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (valueAnimator == null) {

            bitmapRect2 = new Rect(0, 0, snowBitmap.getWidth(), snowBitmap.getHeight());
            desBitmapRect2 = new Rect(0, 0, snowBitmap.getWidth() / 2, snowBitmap.getHeight() / 2);
            bitmapRect3 = new Rect();
            desBitmapRect3 = new Rect();

            handlePathMeasure();

            rect = new Rect(0, 0, getWidth(), getHeight());
            greenShader = new LinearGradient(0, 0, getWidth(), getHeight(), new int[]{getResources().getColor(R.color.c_0043ff), getResources().getColor(R.color.c_008dff)}, null, Shader.TileMode.REPEAT);
            redShader = new LinearGradient(0, 0, getWidth(), getHeight(), new int[]{getResources().getColor(R.color.c_FF6A00), getResources().getColor(R.color.c_F49F1F)}, null, Shader.TileMode.REPEAT);
            gradientPaint.setShader(redShader);
        }
    }

    private void handlePathMeasure() {
        int centerX = (int) (getWidth() / 2.0);
        int centerY = (int) (dp250 + bitmap.getHeight() / 2.0f);
        snowPath.moveTo(0, 0);
        snowPath.lineTo(centerX, centerY);

        pathMeasure = new PathMeasure(snowPath, false);

        snowPath2.moveTo(getWidth(), 0);
        snowPath2.lineTo(centerX, centerY);

        pathMeasure2 = new PathMeasure(snowPath2, false);

        snowPath3.moveTo(getWidth(), getHeight() - dp250);
        snowPath3.lineTo(centerX, centerY);

        pathMeasure3 = new PathMeasure(snowPath3, false);

        initValueAnim(1, pathMeasure);
        initValueAnim(2, pathMeasure2);
        initValueAnim(3, pathMeasure3);

    }


    private void initValueAnim(int type, PathMeasure pathMeasure) {

        float length = pathMeasure.getLength();
        valueAnimator = ValueAnimator.ofFloat(0, length);
        valueAnimator.addUpdateListener(animation -> {
            float animatedValue = (float) animation.getAnimatedValue();
            //mCurrentPosition 传进去,就被复制了
            if (type == 1) {
                pathMeasure.getPosTan(animatedValue, mCurrentPosition, null);
            } else if (type == 2) {
                pathMeasure.getPosTan(animatedValue, mCurrentPosition2, null);
            } else {
                pathMeasure.getPosTan(animatedValue, mCurrentPosition3, null);
            }
            onPercent(animatedValue / length);

            invalidate();
        });
        valueAnimator.setDuration(3000);
        valueAnimator.start();
    }

    private void onPercent(float percent) {
        drawCelsiusText = getLastDoubleValue(MyApplication.PHONE_CELSIUS - ((currentCelsius) * percent)) + "°";
        if (percent > 0.6f) {
            gradientPaint.setShader(greenShader);
        }

        if (coolChangeListener != null) {
            coolChangeListener.onChangePercent(percent);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.drawPath(snowPath, paint);

        canvas.drawRect(rect, gradientPaint);
        canvas.drawBitmap(bitmap, (getWidth() - bitmap.getWidth()) / 2.0f, dp250, paint);

//        String text = "35.1°";

        //画摄氏度的变化
        paint.setTextAlign(Paint.Align.CENTER);
        canvas.drawText(drawCelsiusText, (getWidth()) / 2.0f, dp250 + dp100 + bitmap.getHeight(), paint);

        canvas.drawBitmap(snowBitmap, mCurrentPosition[0], mCurrentPosition[1], paint);
        canvas.drawBitmap(snowBitmap2, mCurrentPosition2[0], mCurrentPosition2[1], paint);
        canvas.drawBitmap(snowBitmap2, mCurrentPosition3[0], mCurrentPosition3[1], paint);
    }

    private Bitmap getBitmap(int drawableRes, boolean isHalf) {
        Drawable drawable = getResources().getDrawable(drawableRes);
        return drawableToBitmap(drawable, isHalf);
    }

    /**
     * Drawable转换成一个Bitmap
     *
     * @param drawable drawable对象
     * @return
     */
    private Bitmap drawableToBitmap(Drawable drawable, boolean isHalf) {
        Bitmap bitmap = null;
        if (isHalf) {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth() / 2, drawable.getIntrinsicHeight() / 2,
                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        } else {
            bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
                    drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
        }

        Canvas canvas = new Canvas(bitmap);
        if (isHalf) {
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth() / 2, drawable.getIntrinsicHeight() / 2);
        } else {
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
        }
        drawable.draw(canvas);
        return bitmap;
    }

    private double getLastDoubleValue(double value) {
        return ((int) (value * 10)) / 10.0;
    }

    private PowerCoolChangeListener coolChangeListener;

    public void setCoolChangeListener(PowerCoolChangeListener coolChangeListener) {
        this.coolChangeListener = coolChangeListener;
    }

    public interface PowerCoolChangeListener {
        void onChangePercent(float percent);
    }
}

PowerCoolLayout是进来的时候的,然后带了个界面,电路板界面的动画效果,中间的个电路板是图片
然后通过canvas.drawText来进行温度的绘制,变化是通过动画来进行变化的

public class GoodChangeLayout extends LinearLayout {

    private ValueAnimator valueAnimator;
    private int currentHeight;
    private TextView tvDec;

    public GoodChangeLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    private void init() {
        setGravity(Gravity.CENTER);
        setOrientation(VERTICAL);
        View.inflate(getContext(), R.layout.view_good_change_layout, this);

        tvDec = findViewById(R.id.tvDec);

//        currentHeight = (getResources().getDisplayMetrics().heightPixels * 2) / 3;
        currentHeight = UiUtils.dp2px(getContext(), 1080);

        valueAnimator = ValueAnimator.ofInt(currentHeight, UiUtils.dp2px(getContext(), 220));
        valueAnimator.setDuration(2000);
        valueAnimator.addUpdateListener(animation -> {
            int animatedValue = (int) animation.getAnimatedValue();
//            layout(0, 0, getWidth(), animatedValue);
            ViewGroup.LayoutParams layoutParams = getLayoutParams();
            layoutParams.height = animatedValue;
            setLayoutParams(layoutParams);
        });
    }

//    @Override
//    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, currentHeight);
//    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

//        if (gradientPaint == null) {
//            gradientPaint = new Paint();
//            greenShader = new LinearGradient(0, 0, getWidth(), currentHeight, new int[]{getResources().getColor(R.color.c_0043ff), getResources().getColor(R.color.c_008dff)}, null, Shader.TileMode.REPEAT);
//            rect = new Rect(0, 0, getWidth(), currentHeight);
//            gradientPaint.setShader(greenShader);
//
//        }
    }

    public void setTvDec(String value) {
        tvDec.setText(value);
    }

    @Override
    protected void onDraw(Canvas canvas) {
//        canvas.drawRect(rect, gradientPaint);
        super.onDraw(canvas);

    }

    public void startAnim() {
        if (valueAnimator.isRunning()) {
            return;
        }
        if (valueAnimator != null) {
            valueAnimator.start();
        }
    }
}

GoodChangeLayout 就是最后显示成功的那个界面,这个界面通过动画改边自己的高度来实现动画,一开始想使用layout来进行实现,发现出现了点问题,只是把本地布局进行了修改

这里记录一下layout,layout的具体是什么意思

public class PowerCoolActivity extends BaseAppCompatActivity {
    public static final String TAG = "PowerCoolActivity";
    private PowerCoolLayout pclLayout;
    private GoodChangeLayout gclLayout;
    private Toolbar mToolBar;

    public static void start(Context context) {
        Intent intent = new Intent(context, PowerCoolActivity.class);
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            Window window = getWindow();
            // Translucent status bar
            window.setFlags(
                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
        setContentView(R.layout.activity_power_cool);
        initToolBar();
        initOtherIds();
    }

    private void initOtherIds() {
        gclLayout = findViewById(R.id.gclLayout);
        pclLayout = findViewById(R.id.pclLayout);
        pclLayout.setCoolChangeListener(percent -> {
            if (percent == 1) {
                pclLayout.setVisibility(View.GONE);
                gclLayout.startAnim();
            }
        });
    }

    private void initToolBar() {
        mToolBar = findViewById(R.id.toolBar);
        mToolBar.setTitle("");
        mToolBar.setTitleTextColor(getResources().getColor(R.color.white));
        mToolBar.setNavigationIcon(R.drawable.white_return);

        setSupportActionBar(mToolBar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    }

    @Override
    public boolean onSupportNavigateUp() {
        finish();
        return super.onSupportNavigateUp();
    }

}

PowerCoolActivity实际是一个展示的载体

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/clear_blue_selector"
    tools:context=".ui.clear.PowerCoolActivity">

    <android.support.v4.widget.NestedScrollView
        android:id="@+id/nsvScroll"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <com.mobi.clearsafe.ui.clear.widget.GoodChangeLayout
                android:id="@+id/gclLayout"
                android:layout_width="match_parent"
                android:layout_height="1080dp" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/white_cron18_selector"
                android:padding="18dp" />

        </LinearLayout>

    </android.support.v4.widget.NestedScrollView>

    <com.mobi.clearsafe.ui.clear.widget.PowerCoolLayout
        android:id="@+id/pclLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/transparent"
        android:fitsSystemWindows="true"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

PowerCoolActivity对应的xml

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容