扫光动效
<p><img src="https://img2024.cnblogs.com/blog/583064/202604/583064-20260423165343426-1382920484.gif"></p><p>使用 LinearGradient 绘制渐变区域,然后旋转角度,可以根据情况跳转扫光区域的大小</p>
<p>针对大量扫光动效同时进行时,需要对绘制进行优化,否则过渡消耗CPU性能</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">drawRectF.set(
max(0f, diffX </span>-<span style="color: rgba(0, 0, 0, 1)"> extraWidth), 0f,
min(width.toFloat(), lightRectF.right </span>+<span style="color: rgba(0, 0, 0, 1)"> extraWidth), mHeight
)<br></span></pre>
<div>
<pre>override fun onDraw(canvas: Canvas) {<br> super.onDraw(canvas)<br> if (!isStart) return<br> canvas.drawRect(drawRectF, paint)<br>}</pre>
</div>
<pre><span style="color: rgba(0, 0, 0, 1)"> </span></pre>
</div>
<p>只绘制扫光区域,并且对不可见区域不做绘制,暂停时不做绘制</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_67f65ea9-8ae0-4e81-9797-a88faff314f5" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_67f65ea9-8ae0-4e81-9797-a88faff314f5" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> com.example.screentest
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.animation.ValueAnimator
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.content.Context
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Canvas
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Color
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.LinearGradient
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Matrix
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Outline
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Paint
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.RectF
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.graphics.Shader
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.util.AttributeSet
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.util.Log
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.view.View
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.view.ViewOutlineProvider
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> android.view.animation.AnticipateOvershootInterpolator
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> androidx.core.animation.doOnEnd
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> androidx.core.content.withStyledAttributes
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.abs
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.cos
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.max
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.min
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> kotlin.math.sin
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
* </span><span style="color: rgba(128, 128, 128, 1)">@author</span><span style="color: rgba(0, 128, 0, 1)"> liuzhen
* 流光动效
* loading drawable
* see
* 圆角
</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
open </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ShimmerView @JvmOverloads constructor(
context: Context, attrs: AttributeSet</span>? = <span style="color: rgba(0, 0, 255, 1)">null</span>, defStyleAttr: Int = 0<span style="color: rgba(0, 0, 0, 1)">
) : View(context, attrs, defStyleAttr) {
companion object {
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">const</span> val TAG = "ShimmerView"
<span style="color: rgba(0, 0, 255, 1)">const</span> val SHIMMER_DURATION = 2000L<span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val shimmerColors =<span style="color: rgba(0, 0, 0, 1)"> intArrayOf(
Color.TRANSPARENT,
resources.getColor(R.color.color_shimmer2, context.theme),
resources.getColor(R.color.color_shimmer1, context.theme),
resources.getColor(R.color.color_shimmer2, context.theme),
Color.TRANSPARENT,
)
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val positions = floatArrayOf(0f, 0.35f, 0.5f, 0.65f<span style="color: rgba(0, 0, 0, 1)">, 1f)
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style =<span style="color: rgba(0, 0, 0, 1)"> Paint.Style.FILL }
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val lightRectF =<span style="color: rgba(0, 0, 0, 1)"> RectF()
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val drawRectF =<span style="color: rgba(0, 0, 0, 1)"> RectF()
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val mShaderMatrix =<span style="color: rgba(0, 0, 0, 1)"> Matrix()
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var diffX =<span style="color: rgba(0, 0, 0, 1)"> 0f
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var isStart = <span style="color: rgba(0, 0, 255, 1)">false</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> var isInit = <span style="color: rgba(0, 0, 255, 1)">false</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> var lightWidth =<span style="color: rgba(0, 0, 0, 1)"> 0f
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var extraWidth =<span style="color: rgba(0, 0, 0, 1)"> 0f
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var mHeight =<span style="color: rgba(0, 0, 0, 1)"> 0f
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var mRotate =<span style="color: rgba(0, 0, 0, 1)"> 30f
</span><span style="color: rgba(0, 0, 255, 1)">private</span> var shimmerType =<span style="color: rgba(0, 0, 0, 1)"> ShimmerType.BANNER.type
</span><span style="color: rgba(0, 0, 255, 1)">private</span> val shimmerAnimator =<span style="color: rgba(0, 0, 0, 1)"> ValueAnimator().apply {
duration </span>=<span style="color: rgba(0, 0, 0, 1)"> SHIMMER_DURATION
repeatCount </span>=<span style="color: rgba(0, 0, 0, 1)"> ValueAnimator.INFINITE
interpolator </span>= AnticipateOvershootInterpolator(0.3f<span style="color: rgba(0, 0, 0, 1)">)
addUpdateListener { anim </span>-><span style="color: rgba(0, 0, 0, 1)">
val num </span>=<span style="color: rgba(0, 0, 0, 1)"> anim.animatedValue as Float
diffX </span>=<span style="color: rgba(0, 0, 0, 1)"> num
updateGradient()
}
doOnEnd {
isStart </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">
diffX </span>=<span style="color: rgba(0, 0, 0, 1)"> lightWidth
updateGradient()
}
}
init {
context.withStyledAttributes(attrs, R.styleable.ShimmerView) {
val shimmerType </span>=<span style="color: rgba(0, 0, 0, 1)"> getInt(R.styleable.ShimmerView_shimmerType, ShimmerType.BANNER.type)
val radius </span>=<span style="color: rgba(0, 0, 0, 1)"> getDimension(R.styleable.ShimmerView_radius, 0f)
init(shimmerType, radius)
}
}
fun init(type: Int, radius: Float) {
shimmerType </span>=<span style="color: rgba(0, 0, 0, 1)"> type
clipToOutline </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
outlineProvider </span>=<span style="color: rgba(0, 0, 0, 1)"> object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(</span>0, 0<span style="color: rgba(0, 0, 0, 1)">, measuredWidth, measuredHeight, radius)
}
}
}
fun startShimmer() {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (shimmerAnimator.isStarted || shimmerAnimator.isRunning || isStart) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
Log.i(TAG, </span>"startShimmer isInit=$isInit"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isInit) {
isStart </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
shimmerAnimator.setFloatValues(</span>-(lightWidth + extraWidth), width +<span style="color: rgba(0, 0, 0, 1)"> lightWidth)
shimmerAnimator.start()
}
}
fun stopShimmer() {
Log.i(TAG, </span>"stopShimmer"<span style="color: rgba(0, 0, 0, 1)">)
shimmerAnimator.cancel()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onSizeChanged(w, h, oldw, oldh)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 根据旋转角度计算合适的绘制区域宽度</span>
val rotationRadians =<span style="color: rgba(0, 0, 0, 1)"> Math.toRadians(mRotate.toDouble())
val cosValue </span>=<span style="color: rgba(0, 0, 0, 1)"> abs(cos(rotationRadians))
val sinValue </span>=<span style="color: rgba(0, 0, 0, 1)"> abs(sin(rotationRadians))
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 计算旋转后需要的额外宽度,确保覆盖整个可见区域</span>
extraWidth = (h * sinValue /<span style="color: rgba(0, 0, 0, 1)"> cosValue).toFloat()
lightWidth </span>= w / <span style="color: rgba(0, 0, 255, 1)">if</span> (shimmerType == ShimmerType.ITEM.type) 1.2f <span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> 4f
mHeight </span>=<span style="color: rgba(0, 0, 0, 1)"> h.toFloat()
isInit </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
log(</span>"onSizeChanged type=$shimmerType,width=$w,height=$h,lightWidth=$lightWidth,extraWidth=$extraWidth"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">isStart) startShimmer()
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> fun updateGradient() {
mShaderMatrix.reset()
lightRectF.set(diffX, 0f, diffX </span>+<span style="color: rgba(0, 0, 0, 1)"> lightWidth, mHeight)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置可见区域,避免多余消耗</span>
<span style="color: rgba(0, 0, 0, 1)"> drawRectF.set(
max(0f, diffX </span>-<span style="color: rgba(0, 0, 0, 1)"> extraWidth), 0f,
min(width.toFloat(), lightRectF.right </span>+<span style="color: rgba(0, 0, 0, 1)"> extraWidth), mHeight
)
paint.shader </span>=<span style="color: rgba(0, 0, 0, 1)"> LinearGradient(
lightRectF.left, lightRectF.top,
lightRectF.right, lightRectF.top,
shimmerColors, positions,
Shader.TileMode.CLAMP
).apply {
mShaderMatrix.setRotate(mRotate, lightRectF.centerX(), lightRectF.centerY())
setLocalMatrix(mShaderMatrix)
}
invalidate()
}
override fun onDraw(canvas: Canvas) {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onDraw(canvas)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!isStart) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
canvas.drawRect(drawRectF, paint)
}
override fun onAttachedToWindow() {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onAttachedToWindow()
startShimmer()
}
override fun onDetachedFromWindow() {
</span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">.onDetachedFromWindow()
Log.i(TAG, </span>"onDetachedFromWindow type=$shimmerType"<span style="color: rgba(0, 0, 0, 1)">)
stopShimmer()
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> fun log(str: String) =<span style="color: rgba(0, 0, 0, 1)"> Log.i(TAG, str)
}
</span><span style="color: rgba(0, 0, 255, 1)">enum</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ShimmerType(val type: Int) {
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 流光宽度较小 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
BANNER(</span>0<span style="color: rgba(0, 0, 0, 1)">),
</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> 流光宽度较大 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
ITEM(</span>1<span style="color: rgba(0, 0, 0, 1)">),
}</span></pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<div class="cnblogs_code"><img id="code_img_closed_9b6177cc-4b84-49e4-a136-dcd594651080" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_9b6177cc-4b84-49e4-a136-dcd594651080" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_9b6177cc-4b84-49e4-a136-dcd594651080" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">FrameLayout </span><span style="color: rgba(255, 0, 0, 1)">xmlns:android</span><span style="color: rgba(0, 0, 255, 1)">="http://schemas.android.com/apk/res/android"</span><span style="color: rgba(255, 0, 0, 1)">
xmlns:app</span><span style="color: rgba(0, 0, 255, 1)">="http://schemas.android.com/apk/res-auto"</span><span style="color: rgba(255, 0, 0, 1)">
android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/main"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">com.example.screentest.ShimmerView
</span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/shimmer_view1"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="match_parent"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="350dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_marginHorizontal</span><span style="color: rgba(0, 0, 255, 1)">="50dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_marginTop</span><span style="color: rgba(0, 0, 255, 1)">="20dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:background</span><span style="color: rgba(0, 0, 255, 1)">="@android:color/background_dark"</span><span style="color: rgba(255, 0, 0, 1)">
app:radius</span><span style="color: rgba(0, 0, 255, 1)">="24dp"</span><span style="color: rgba(255, 0, 0, 1)">
app:shimmerType</span><span style="color: rgba(0, 0, 255, 1)">="banner"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">com.example.screentest.ShimmerView
</span><span style="color: rgba(255, 0, 0, 1)">android:id</span><span style="color: rgba(0, 0, 255, 1)">="@+id/shimmer_view2"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_width</span><span style="color: rgba(0, 0, 255, 1)">="530dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_height</span><span style="color: rgba(0, 0, 255, 1)">="300dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_marginHorizontal</span><span style="color: rgba(0, 0, 255, 1)">="50dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:layout_marginTop</span><span style="color: rgba(0, 0, 255, 1)">="400dp"</span><span style="color: rgba(255, 0, 0, 1)">
android:background</span><span style="color: rgba(0, 0, 255, 1)">="@android:color/background_dark"</span><span style="color: rgba(255, 0, 0, 1)">
app:radius</span><span style="color: rgba(0, 0, 255, 1)">="24dp"</span><span style="color: rgba(255, 0, 0, 1)">
app:shimmerType</span><span style="color: rgba(0, 0, 255, 1)">="item"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">FrameLayout</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<span class="cnblogs_code_collapse">activity_test</span></div>
<div class="cnblogs_code"><img id="code_img_closed_7b64aa0b-57da-4062-b693-76b61b2de905" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img id="code_img_opened_7b64aa0b-57da-4062-b693-76b61b2de905" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_7b64aa0b-57da-4062-b693-76b61b2de905" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">declare-styleable </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="ShimmerView"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> Sets a drawable as the content of this ImageView. </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">attr </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="src"</span><span style="color: rgba(255, 0, 0, 1)"> format</span><span style="color: rgba(0, 0, 255, 1)">="reference|color"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> com.example.screentest.ShimmerType </span><span style="color: rgba(0, 128, 0, 1)">--></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">attr </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="shimmerType"</span><span style="color: rgba(255, 0, 0, 1)"> format</span><span style="color: rgba(0, 0, 255, 1)">="enum"</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">enum </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="banner"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="0"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">enum </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="item"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="1"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">attr</span><span style="color: rgba(0, 0, 255, 1)">></span>
<span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">attr </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="radius"</span><span style="color: rgba(255, 0, 0, 1)"> format</span><span style="color: rgba(0, 0, 255, 1)">="dimension"</span> <span style="color: rgba(0, 0, 255, 1)">/></span>
<span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">declare-styleable</span><span style="color: rgba(0, 0, 255, 1)">></span></pre>
</div>
<span class="cnblogs_code_collapse">attrs</span></div>
<p><img alt="image" width="784" height="274" loading="lazy" src="https://img2024.cnblogs.com/blog/583064/202604/583064-20260423170915891-2073693300.png"></p>
<p>非旋转状态下起始位置绘制</p>
<p><img src="https://img2024.cnblogs.com/blog/583064/202604/583064-20260423170807026-889078893.png"></p>
<p>旋转30度后,在起始位置绘制</p>
<p> </p><br><br>
来源:https://www.cnblogs.com/LiuZhen/p/19917206
頁:
[1]