• 自定义控件——通过持续绘制实现简单动画——重新绘制视图界面


    重新绘制视图界面

    不管是setText方法还是setImageBitmap方法,它们内部都调用了invalidate方法,该方法用来刷新控件界面。

    类似的方法说明如下:


    (1)invalidate方法,它不是线程安全的,只保证在主线程(UI线程)中能够正常刷新视图。


    (2)postInvalidate方法,它是线程安全的,即使在分线程中调用也能正常刷新视图。


    (3)postInvalidateDelayed方法,允许延迟一段时间后再刷新视图。

    ======================================================================================================================

    布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="5dp">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="40dp">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="刷新方式:"
                android:textColor="@color/black"
                android:textSize="17sp" />
    
            <Spinner
                android:id="@+id/sp_refresh"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="left|center"
                android:spinnerMode="dialog" />
        </LinearLayout>
    
        <!-- 自定义的椭圆视图,需要使用全路径 -->
        <com.example.myapplication.widget.OvalView
            android:id="@+id/ov_validate"
            android:layout_width="match_parent"
            android:layout_height="150dp" />
    
    </LinearLayout>

    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:singleLine="true"
        android:gravity="center"
        android:textSize="17sp"
        android:textColor="#0000ff" />

    主代码:

    package com.example.myapplication;
    
    import androidx.appcompat.app.AppCompatActivity;
    import android.annotation.SuppressLint;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;
    import com.example.myapplication.widget.OvalView;
    
    @SuppressLint("SetTextI18n")
    public class MainActivity extends AppCompatActivity
    {
    
        private OvalView ov_validate; // 声明一个椭圆视图对象
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
    
            ov_validate = findViewById(R.id.ov_validate);
    
    
            initRefreshSpinner(); // 初始化刷新方式的下拉框
        }
    
        // 初始化刷新方式的下拉框
        private void initRefreshSpinner()
        {
            ArrayAdapter<String> refreshAdapter = new ArrayAdapter<String>(this, R.layout.item_select, refreshArray);
    
            Spinner sp_refresh = findViewById(R.id.sp_refresh);
            sp_refresh.setPrompt("请选择刷新方式"); // 设置下拉框的标题
            sp_refresh.setAdapter(refreshAdapter); // 设置下拉框的数组适配器
            sp_refresh.setSelection(0); // 设置下拉框默认显示第一项
            // 给下拉框设置选择监听器,一旦用户选中某一项,就触发监听器的onItemSelected方法
            sp_refresh.setOnItemSelectedListener(new RefreshSelectedListener());
        }
    
        private String[] refreshArray = {
                "主线程调用invalidate",
                "主线程调用postInvalidate",
                "延迟3秒后刷新",
                "分线程调用invalidate",
                "分线程调用postInvalidate"
        };
        
        class RefreshSelectedListener implements AdapterView.OnItemSelectedListener 
        {
            public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) 
            {
                
                if (arg2 == 0) {  // 主线程调用invalidate
                    ov_validate.invalidate(); // 刷新视图(用于主线程)
                } 
                else if (arg2 == 1) {  // 主线程调用postInvalidate
                    ov_validate.postInvalidate(); // 刷新视图(主线程和分线程均可使用)
                } 
                else if (arg2 == 2) {  // 延迟3秒后刷新
                    ov_validate.postInvalidateDelayed(3000); // 延迟若干时间后再刷新视图
                }
                else if (arg2 == 3) {  // 分线程调用invalidate
                    // invalidate不是线程安全的,虽然下面代码在分线程中调用invalidate方法也没报错,但在复杂场合可能出错
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            ov_validate.invalidate(); // 刷新视图(用于主线程)
                        }
                    }).start();
                }
                else if (arg2 == 4) {  // 分线程调用postInvalidate
                    // postInvalidate是线程安全的,分线程中建议调用postInvalidate方法来刷新视图
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            ov_validate.postInvalidate(); // 刷新视图(主线程和分线程均可使用)
                        }
                    }).start();
                }
            }
    
            public void onNothingSelected(AdapterView<?> arg0) {}
        }
    
    }

     

    OvalView
    package com.example.myapplication.widget;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.RectF;
    import android.util.AttributeSet;
    import android.view.View;
    
    public class OvalView extends View
    {
        private Paint mPaint = new Paint(); // 创建一个画笔对象
    
        private int mDrawingAngle = 0; // 当前绘制的角度
    
        public OvalView(Context context)
        {
    
            this(context, null);
        }
    
        public OvalView(Context context, AttributeSet attrs)
        {
    
            super(context, attrs);
            mPaint.setColor(Color.RED); // 设置画笔的颜色
        }
    
        @Override
        protected void onDraw(Canvas canvas)
        {
            super.onDraw(canvas);
    
            mDrawingAngle += 30; // 绘制角度增加30度
    
            int width = getMeasuredWidth(); // 获得布局的实际宽度
    
            int height = getMeasuredHeight(); // 获得布局的实际高度
    
            RectF rectf = new RectF(0, 0, width, height); // 创建扇形的矩形边界
    
            // 在画布上绘制指定角度的扇形。第四个参数为true表示绘制扇形,为false表示绘制圆弧
            canvas.drawArc(rectf, 0, mDrawingAngle, true, mPaint);
        }
    
    }

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    浮点数小数点后开始非零数字的起始位置
    关于接口测试
    性能测试模型之曲线拐点模型
    2018春招实习笔试面试总结(PHP)
    mysql删除表中的记录
    浅析单点登录
    MySQL两种引擎的比较
    Redis初探(windows/linux安装)
    剑指offer试题(PHP篇三)
    剑指offer试题(PHP篇二)
  • 原文地址:https://www.cnblogs.com/xiaobaibailongma/p/16653142.html
Copyright © 2020-2023  润新知