要做的效果传统的View方式
自定义一个控件,继承View。onDraw()中在canvas上画12个小圈。
首先定义控件使用的属性,在valuse目录下创建一个attrs.xml。
<resources> <declare-styleable name="HyLoadingView"> <attr name="hy_size" format="dimension" /> <attr name="hy_color" format="color" /> <attr name="hy_duration" format="integer" /> declare-styleable>resources>
编写自定义控件代码
class HyLoadingView(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : View(context, attrs, defStyleAttr) { constructor(context: Context) : this(context, null, 0) constructor(context: Context, attrs: AttributeSet? = null) : this(context, attrs, 0) /** * 小圆总数 */ private val circleCount = 12 /** * 小圆圆心之间间隔角度差 */ private val degreePerCircle = 360 / circleCount /** * 记录所有小圆半径 */ private val mWholeCircleRadius = FloatArray(circleCount) /** * 记录所有小圆颜色 */ private val mWholeCircleColors = IntArray(circleCount) /** * 小圆最大半径 */ private var mMaxCircleRadius = 0f /** * 控件大小 */ private var mSize = 0 /** * 小圆颜色 */ private var mColor = 0 /** * 画笔 */ private lateinit var mPaint: Paint private var mAnimator: ValueAnimator? = null private var mAnimateValue = 1 /** * 动画时长 */ private var mDuration = 0L /** * 动画监听 */ private val mUpdateListener = AnimatorUpdateListener { animation -> mAnimateValue = animation.animatedValue as Int invalidate() } init { initAttrs(context, attrs) initPaint() initValue() } /** * 初始化自定义属性 */ private fun initAttrs(context: Context, attrs: AttributeSet?) { val ta = context.obtainStyledAttributes(attrs, R.styleable.HyLoadingView) mSize = ta.getDimensionPixelSize( R.styleable.HyLoadingView_hy_size, DimensionUtils.withDIP(100f).toPX().toInt() ) setSize(mSize) mColor = ta.getColor(R.styleable.HyLoadingView_hy_color, Color.parseColor("#333333")) setColor(mColor) mDuration = ta.getInt(R.styleable.HyLoadingView_hy_duration, 1500).toLong() ta.recycle() } /** * 初始化画笔 */ private fun initPaint() { mPaint = Paint().apply { isAntiAlias = true //抗锯齿 isDither = true //防抖动
使用
id="@+id/loadingView"android:layout_width="wrap_content"android:layout_height="wrap_content"app:hy_size="40dp"app:hy_color="#666666" />Jetpack Compose的自定义控件
定义与编写
@Composablefun HyLoadingView(size: Dp = 50.dp, color: Color = Color(0xff333333)) { var mDegrees by remember { mutableStateOf(0f) } Canvas( modifier = Modifier .rotate(mDegrees) .size(size) ) { val minCircleRadius = size.value / 8.5f var degrees = 0f for (i in 0..11) { degrees += 360 / 12f val radius: Float val alpha: Float when (i) { 7 -> { radius = minCircleRadius * 1.25f alpha = 0.7f } 8 -> { radius = minCircleRadius * 1.5f alpha = 0.8f } 9 -> { radius = minCircleRadius * 1.75f alpha = 0.9f } 10 -> { radius = minCircleRadius * 2.0f alpha = 1f } 11 -> { radius = minCircleRadius * 1.75f alpha = 0.9f } else -> { radius = minCircleRadius alpha = 0.5f } } rotate(degrees) { drawCircle( color = color, radius = radius, center = center.div(2f), alpha = alpha ) } } } val scope = rememberCoroutineScope() LaunchedEffect(scope) { scope.launch { flow { for (i in 0..Int.MAX_VALUE) { emit(i) delay(2) } }.flowOn(Dispatchers.Default).collect { mDegrees = it.toFloat() } } }}
使用之
HyLoadingView(100.dp, MaterialTheme.colors.primary)很随便的说两句
做这个东西的思路是:计算好第一个圆的大小、位置、颜色(透明度),画出来;然后旋转角度,再画一个……画完之后,加上个动画就行了。
对比一下代码,明显使用Jetpack Compose更简洁。Jetpack Compose很优秀。
热门跟贴