美文网首页
自定义view和属性动画相关

自定义view和属性动画相关

作者: 向前的zz | 来源:发表于2020-03-23 16:32 被阅读0次

上实现效果


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

相关文章

  • Android - 自定义View和属性动画 ValueAnim

    自定义View和属性动画ValueAnimator实现圆点指示器 自定义View和属性动画相结合实现支持动态修改指...

  • 动画深入研究

    前言 分类 View动画,帧动画,自定义View动画,属性动画 View动画 平移,缩放,旋转,透明Transla...

  • Android动画深入分析

    导语 本章学习内容:介绍View动画和自定义View动画,View动画一些特殊的使用场景,对属性动画全面性的介绍,...

  • 自定义view和属性动画相关

    上实现效果 这个效果是通过两个布局,分别都有动画效果来进行实现的 PowerCoolLayout是进来的时候的,然...

  • 自定义view(三)----自定义字体变色

    上一篇文章我们使用属性动画实现了自定义view的动画效果,这篇文章主要是结合属性动画自定义一个文字变色的view。...

  • Android日志:自定义炫酷进度

    前几期涉及到了自定义View以及属性动画的使用,这次利用一个模拟网络下载的自定义炫酷进度对自定义View和动画进行...

  • Android知识总结

    一、Android动画 Android 属性动画:这是一篇很详细的 属性动画 总结&攻略 二、自定义View 爱哥...

  • Android读书笔记(7)—— Android动画深入分析

    一、View动画 Android动画分为三种:View动画、帧动画和属性动画。 1、View动画的种类 View动...

  • Android UI 绘制面试题

    1.1 Android 补间动画和属性动画的区别? 特性补间动画属性动画view 动画支持支持非view动画不支持...

  • Android UI 绘制面试题

    1.1 Android 补间动画和属性动画的区别? 特性补间动画属性动画view 动画支持支持非view动画不支持...

网友评论

      本文标题:自定义view和属性动画相关

      本文链接:https://www.haomeiwen.com/subject/ycbwyhtx.html