一、前言
上节 讲解了旋转圆环基本的实现方法。本文将在此基础上进一步改进,在属性文件中自定义控件属性,避免代码中显式调用setXXX() 方法。
二、流程
首先,在资源文件 values 中新建一个 attr.xml,其中定义了我们即将使用的几个旋转环的属性,如下所示
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RotatingRing"> <attr name="width" format="integer"/> <attr name="radius" format="integer"/> <attr name="start_angle" format="integer"/> <attr name="sweep_angle" format="integer"/> <attr name="start_color" format="color"/> <attr name="end_color" format="color"/> <attr name="color" format="color"/> <attr name="duration" format="integer"/> </declare-styleable> </resources>
在 RotatingRing 类中,添加第三个构造函数 (含3个参数的),如下所示
public RotatingRing(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
根据属性清单获取属性值
public RotatingRing(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotatingRing); radius = typedArray.getInt(R.styleable.RotatingRing_radius, 100); width = typedArray.getInt(R.styleable.RotatingRing_width, 20); startAngle = typedArray.getInt(R.styleable.RotatingRing_start_angle, 0); sweepAngle = typedArray.getInt(R.styleable.RotatingRing_sweep_angle, 270); startColor = typedArray.getColor(R.styleable.RotatingRing_start_color, Color.WHITE); endColor = typedArray.getColor(R.styleable.RotatingRing_end_color, typedArray.getColor(R.styleable.RotatingRing_color, Color.BLUE)); duration = typedArray.getColor(R.styleable.RotatingRing_duration, 1000); typedArray.recycle(); }
由上所述,默认值可以被第三个构造函数所定义,故可以去除第一个构造函数里定义的的默认值,改进后的构造函数如下所示
public RotatingRing(Context context) { this(context, null); } public RotatingRing(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public RotatingRing(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotatingRing); radius = typedArray.getInt(R.styleable.RotatingRing_radius, 100); width = typedArray.getInt(R.styleable.RotatingRing_width, 20); startAngle = typedArray.getInt(R.styleable.RotatingRing_start_angle, 0); sweepAngle = typedArray.getInt(R.styleable.RotatingRing_sweep_angle, 270); startColor = typedArray.getColor(R.styleable.RotatingRing_start_color, Color.WHITE); endColor = typedArray.getColor(R.styleable.RotatingRing_end_color, typedArray.getColor(R.styleable.RotatingRing_color, Color.BLUE)); duration = typedArray.getColor(R.styleable.RotatingRing_duration, 1000); typedArray.recycle(); }
到此,可以去除 MainActivity 中的 RotatingRing.setXXX()方法,而在 activity_main.xml 里定义属性
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.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" tools:context=".MainActivity"> <draw.bitmap.canvas.RotatingRing android:id="@+id/rotating_ring" android:layout_width="400dp" android:layout_height="400dp" app:width="30" app:radius="150" app:start_angle="0" app:sweep_angle="270" app:duration="1500" app:start_color="@color/colorWhite" app:end_color="@color/colorRed" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
其中‘app’为原布局文件里定义好的命名空间,这里我直接拿来用了,也可以自己定义命名空间,只须在布局文件头加上
xmlns:命名空间="http://schemas.android.com/apk/res-auto"
这里我为区分定义了一个红色的圆环,而其他参数与原先 MainActivity 里setXXX() 方法里的参数一致,修改后的代码为
import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { RotatingRing rotatingRing; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); rotatingRing = findViewById(R.id.rotating_ring); rotatingRing.startAnim(); } }
运行效果
到此已经初步掌握了自定义view的一些必要性质,下一节将深入了解一些高级属性以及绘制相关源码等。