Skip to content

Commit 603ecb6

Browse files
committed
#
1 parent 18d5d95 commit 603ecb6

File tree

7 files changed

+151
-21
lines changed

7 files changed

+151
-21
lines changed

app/src/main/java/com/demo/app/MainActivity.kt

+12
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ package com.demo.app
22

33
import android.content.res.ColorStateList
44
import android.graphics.Color
5+
import android.graphics.drawable.LayerDrawable
6+
import android.graphics.drawable.ScaleDrawable
57
import androidx.appcompat.app.AppCompatActivity
68
import android.os.Bundle
9+
import android.util.Log
710
import android.view.ViewGroup
11+
import android.widget.ProgressBar
812
import com.demo.app.databinding.ActivityMainBinding
913
import com.google.android.material.shape.MarkerEdgeTreatment
1014
import com.google.android.material.shape.MaterialShapeDrawable
@@ -33,6 +37,14 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
3337
strokeWidth = 2f.dp
3438
strokeColor = ColorStateList.valueOf(Color.RED)
3539
}
40+
41+
binding.pb1.setOnClickListener { (it as ProgressBar).update() }
42+
binding.pb2.setOnClickListener { (it as ProgressBar).update() }
43+
binding.pb3.setOnClickListener { (it as ProgressBar).update() }
44+
}
45+
46+
private fun ProgressBar.update() {
47+
progress = (progress + 1) % 100
3648
}
3749

3850
private val Float.dp: Float get() = resources.displayMetrics.density * this
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools">
5+
<item android:id="@android:id/background">
6+
<me.reezy.cosmo.shapeable.ShapeableDrawable
7+
app:backgroundTint="#33000000"
8+
app:cornerSize="5dp"
9+
app:cornerType="cut" />
10+
</item>
11+
<item android:id="@android:id/progress">
12+
<scale
13+
android:scaleWidth="100%"
14+
android:useIntrinsicSizeAsMinimum="true">
15+
<me.reezy.cosmo.shapeable.ShapeableDrawable
16+
android:width="10dp"
17+
app:cornerSize="5dp"
18+
app:cornerType="cut"
19+
app:gradientEndColor="#28000000"
20+
app:gradientOrientation="LEFT_RIGHT"
21+
app:gradientStartColor="#06000000" />
22+
</scale>
23+
</item>
24+
</layer-list>

app/src/main/res/layout/activity_main.xml

+34-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
android:layout_width="match_parent"
66
android:layout_height="match_parent"
77
android:layout_gravity="center"
8-
android:background="@color/purple_200"
98
android:clipChildren="false"
109
android:columnCount="3"
1110
android:orientation="horizontal"
@@ -120,7 +119,7 @@
120119
app:shadowColor="#40ffffff"
121120
app:shadowRadius="10dp"
122121
app:strokeColor="@color/teal_700"
123-
app:strokeWidth="0dp" />
122+
app:strokeWidth="0dp" />
124123

125124
<View
126125
android:layout_width="200dp"
@@ -141,4 +140,37 @@
141140
android:background="#400000cc" />
142141

143142

143+
144+
<ProgressBar
145+
android:id="@+id/pb_1"
146+
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
147+
android:layout_width="300dp"
148+
android:layout_columnSpan="3"
149+
android:layout_marginTop="20dp"
150+
android:layout_gravity="center_horizontal"
151+
android:layout_height="30dp"
152+
android:progressDrawable="@drawable/progress"
153+
android:max="10000"
154+
android:progress="1" />
155+
156+
<ProgressBar
157+
android:id="@+id/pb_2"
158+
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
159+
android:layout_width="300dp"
160+
android:layout_columnSpan="3"
161+
android:layout_marginTop="20dp"
162+
android:layout_gravity="center_horizontal"
163+
android:layout_height="30dp"
164+
android:progressDrawable="@drawable/progress"
165+
android:progress="1" />
166+
<ProgressBar
167+
android:id="@+id/pb_3"
168+
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
169+
android:layout_width="300dp"
170+
android:layout_columnSpan="3"
171+
android:layout_marginTop="20dp"
172+
android:layout_gravity="center_horizontal"
173+
android:layout_height="30dp"
174+
android:progressDrawable="@drawable/progress"
175+
android:progress="50" />
144176
</GridLayout>

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ cosmoRepoPath=https://gitee.com/ezy/repo/raw/cosmo
2929
buildGradlePath=https://gitee.com/ezy/gradle/raw/cosmo
3030

3131
LIBRARY_GROUP=me.reezy.cosmo
32-
LIBRARY_VERSION=0.10.1
32+
LIBRARY_VERSION=0.10.2
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
22
xmlns:tools="http://schemas.android.com/tools"
3-
package="me.reezy.cosmo">
3+
package="me.reezy.cosmo.shapeable">
44
</manifest>

shapeable/src/main/java/me/reezy/cosmo/shapeable/ShapeableDrawable.kt

+76-17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ import android.graphics.Rect
1414
import android.graphics.RectF
1515
import android.graphics.Shader
1616
import android.graphics.SweepGradient
17+
import android.graphics.drawable.Drawable
1718
import android.graphics.drawable.GradientDrawable
19+
import android.os.Build
1820
import android.util.AttributeSet
21+
import android.util.Log
1922
import android.util.TypedValue
2023
import androidx.core.content.res.TypedArrayUtils.obtainAttributes
2124
import androidx.core.graphics.ColorUtils
@@ -30,28 +33,34 @@ import com.google.android.material.shape.RelativeCornerSize
3033
import com.google.android.material.shape.RoundedCornerTreatment
3134
import com.google.android.material.shape.ShapeAppearanceModel
3235
import com.google.android.material.shape.ShapeAppearancePathProvider
33-
import me.reezy.cosmo.R
3436
import org.xmlpull.v1.XmlPullParser
3537
import kotlin.math.PI
3638
import kotlin.math.atan
3739
import kotlin.math.min
3840
import kotlin.math.sqrt
3941

42+
@Suppress("NOTHING_TO_INLINE")
4043
@SuppressLint("RestrictedApi")
41-
class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawable(shapeModel) {
44+
class ShapeableDrawable private constructor(state: ShapeableState, msdState: MaterialShapeDrawableState, isNew: Boolean = true) : MaterialShapeDrawable(msdState) {
45+
46+
private var constantState: RealConstantState = RealConstantState(state, msdState)
47+
48+
private val clipRect: RectF = RectF()
49+
50+
val clipPath = Path()
51+
4252
init {
4353
fieldShadowRenderer.set(this, RealShadowRenderer())
44-
shadowCompatibilityMode = SHADOW_COMPAT_MODE_ALWAYS
45-
setUseTintColorForShadow(true)
46-
tintList = ColorStateList.valueOf(Color.TRANSPARENT)
54+
if (isNew) {
55+
shadowCompatibilityMode = SHADOW_COMPAT_MODE_ALWAYS
56+
setUseTintColorForShadow(true)
57+
tintList = ColorStateList.valueOf(Color.TRANSPARENT)
58+
}
4759
}
4860

49-
val clipPath = Path()
50-
51-
private val clipRect: RectF = RectF()
52-
private val gradientState = GradientState()
61+
constructor() : this(ShapeableState(), MaterialShapeDrawableState(ShapeAppearanceModel(), null))
5362

54-
constructor() : this(ShapeAppearanceModel())
63+
constructor(shapeModel: ShapeAppearanceModel) : this(ShapeableState(), MaterialShapeDrawableState(shapeModel, null))
5564

5665
constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0)
5766
: this(ShapeAppearanceModel.builder(context, attrs, defStyleAttr, defStyleRes).build()) {
@@ -69,8 +78,22 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
6978
ta.recycle()
7079
}
7180

81+
override fun getIntrinsicWidth(): Int = shapeableState.width
82+
override fun getIntrinsicHeight(): Int = shapeableState.height
83+
override fun getConstantState(): ConstantState = constantState
84+
85+
override fun mutate(): Drawable {
86+
super.mutate()
87+
constantState = RealConstantState(ShapeableState(shapeableState), super.getConstantState() as MaterialShapeDrawableState)
88+
return this
89+
}
90+
91+
private val shapeableState: ShapeableState get() = constantState.shapeable
7292

7393
private fun initAttrs(a: TypedArray) {
94+
95+
shapeableState.init(a)
96+
7497
strokeColor = a.getColorStateList(R.styleable.ShapeableDrawable_strokeColor)
7598
strokeWidth = a.getDimensionPixelSize(R.styleable.ShapeableDrawable_strokeWidth, 0).toFloat()
7699

@@ -81,17 +104,16 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
81104
setCorners(cornerPosition, cornerSize, cornerType)
82105
}
83106

84-
// 渐变背景色
85-
gradientState.loadFromAttrs(a)
86107

87-
if (gradientState.gradientColors != null) {
108+
if (shapeableState.gradientColors != null) {
88109
setUseTintColorForShadow(false)
89110
tintList = null
90111
} else {
91112
setUseTintColorForShadow(true)
92113
tintList = a.getColorStateList(R.styleable.ShapeableDrawable_backgroundTint) ?: ColorStateList.valueOf(Color.TRANSPARENT)
93114
}
94115

116+
95117
// 阴影
96118
if (a.hasValue(R.styleable.ShapeableDrawable_shadowRadius)) {
97119
shadowRadius = a.getDimensionPixelSize(R.styleable.ShapeableDrawable_shadowRadius, 0)
@@ -198,10 +220,11 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
198220
}
199221

200222
override fun onBoundsChange(bounds: Rect) {
223+
Log.e("OoO", "${hashCode()}.onBoundsChange($bounds) width = ${shapeableState.width}")
201224
super.onBoundsChange(bounds)
202225
updateClipPath(bounds.width(), bounds.height())
203226

204-
gradientState.createFillShader(bounds.toRectF())?.let {
227+
shapeableState.createFillShader(bounds.toRectF())?.let {
205228
(fieldFillPaint.get(this) as Paint).shader = it
206229
}
207230
invalidateSelf()
@@ -234,8 +257,11 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
234257
}
235258

236259

260+
private class ShapeableState() {
261+
237262

238-
private class GradientState {
263+
var width: Int = -1
264+
var height: Int = -1
239265

240266
var gradientColors: IntArray? = null
241267
var gradientType: Int = GradientDrawable.LINEAR_GRADIENT
@@ -244,7 +270,22 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
244270
var gradientCenterY: Float = 0.5f
245271
var gradientRadius: Float = 0.5f
246272

247-
fun loadFromAttrs(a: TypedArray) {
273+
constructor(orig: ShapeableState) : this() {
274+
width = orig.width
275+
height = orig.height
276+
277+
gradientColors = orig.gradientColors
278+
gradientType = orig.gradientType
279+
gradientOrientation = orig.gradientOrientation
280+
gradientCenterX = orig.gradientCenterX
281+
gradientCenterY = orig.gradientCenterY
282+
gradientRadius = orig.gradientRadius
283+
}
284+
285+
286+
fun init(a: TypedArray) {
287+
width = a.getDimensionPixelSize(R.styleable.ShapeableDrawable_android_width, -1)
288+
height = a.getDimensionPixelSize(R.styleable.ShapeableDrawable_android_height, -1)
248289

249290
gradientColors = a.getGradientColors()
250291
gradientType = a.getInt(R.styleable.ShapeableDrawable_gradientType, GradientDrawable.LINEAR_GRADIENT)
@@ -257,6 +298,7 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
257298
GradientDrawable.Orientation.TOP_BOTTOM
258299
}
259300
}
301+
260302
fun createFillShader(rect: RectF): Shader? = when {
261303
gradientColors == null -> null
262304
gradientType == GradientDrawable.LINEAR_GRADIENT -> {
@@ -270,7 +312,12 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
270312
GradientDrawable.Orientation.LEFT_RIGHT -> RectF(rect.left, rect.top, rect.right, rect.top)
271313
else -> RectF(rect.left, rect.top, rect.right, rect.bottom)
272314
}
273-
LinearGradient(r.left, r.top, r.right, r.bottom, gradientColors!!, null, Shader.TileMode.CLAMP)
315+
val tileMode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
316+
Shader.TileMode.DECAL
317+
} else {
318+
Shader.TileMode.CLAMP
319+
}
320+
LinearGradient(r.left, r.top, r.right, r.bottom, gradientColors!!, null, tileMode)
274321
}
275322

276323
gradientType == GradientDrawable.RADIAL_GRADIENT -> {
@@ -306,6 +353,18 @@ class ShapeableDrawable(shapeModel: ShapeAppearanceModel) : MaterialShapeDrawabl
306353
}
307354
return null
308355
}
356+
357+
}
358+
359+
360+
private class RealConstantState(val shapeable: ShapeableState, val msd: MaterialShapeDrawableState) : ConstantState() {
361+
override fun newDrawable(): Drawable {
362+
val d = ShapeableDrawable(ShapeableState(shapeable), msd, false)
363+
d.invalidateSelf()
364+
return d
365+
}
366+
367+
override fun getChangingConfigurations(): Int = 0
309368
}
310369

311370
private class RealShadowRenderer : ShadowRenderer() {

shapeable/src/main/res/values/values-shapeable.xml

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<resources>
33

44
<declare-styleable name="ShapeableDrawable">
5+
<attr name="android:width" />
6+
<attr name="android:height" />
7+
58
<!-- 背景色 -->
69
<attr name="backgroundTint" />
710

0 commit comments

Comments
 (0)