Compose挑燈夜看 - 照亮手機螢幕裡面的書本內容
theme: smartblue
攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第7天,點選檢視活動詳情。
一、前言
上一篇文章 Compose回憶童年 - 手拉燈繩-開燈/關燈裡面82年鎢絲燈,讓我又有了新的想法,我們怎麼照亮手機裡面的文字內容呢?
我們會在上一篇文章的基礎上來實現“挑燈夜看”的功能,怎麼下手呢?往下看👇
二、文字著色器
我們想要實現照亮功能,那肯定需要有不亮的文字內容。
通過透明度來可以嗎?肯定不行,文字內容是可以上下滑動的,是一個整體,我們不能通過透明度來做。
在看到小米手機的文字著色效果之後:
我知道如何下手了,我先來看看Compose
的Text
如何做漸變著色?
1. 有些同學可能喜歡用Canvas
去繪製:
kotlin
Canvas(...) {
drawIntoCanvas { canvas ->
canvas.nativeCanvas.drawText(text, x, y, paint)
}
}
2. 我們可以使用Modifeir的drawWithCache修飾符,官方文件的連結裡面也給我們了不少示例。
kotlin
Text(
text = "永遠相信美好的事情即將發生❤️",
modifier = Modifier
.graphicsLayer(alpha = 0.99f)
.drawWithCache {
val brush = Brush.horizontalGradient(
listOf(
Color(0xFFE24CE2),
Color(0xFF73BB70),
Color(0xFFE24CE2)
)
)
onDrawWithContent {
drawContent()
drawRect(brush, blendMode = BlendMode.SrcAtop)
}
}
)
上面程式碼,我們使用到了BlendMode,我們這裡用的是BlendMode#SrcAtop
:
將源影象合成到目標影象上,僅限於與目標重疊的位置,確保只有文字可見並且矩形的其餘部分被剪下。
3. Google在Compose1.2.0-beta01的API變更裡面,向TextStyle
和SpanStyle
添加了 Brush
API,以提供使用漸變顏色繪製文字的方法。
kotlin
private val GradientColors = listOf(
Color(0xFF00FFFF), Color(0xFF97E063),
Color(0xFFE24CE2), Color(0xFF97E063)
)
Text(
modifier = Modifier.align(Alignment.Center).requiredWidthIn(max = 250.dp),
text = "永遠相信美好的事情即將發生❤️,我們不會期待米粉的期待!\n\n兄弟們支援了嗎?",
style = TextStyle(
brush = Brush.linearGradient(
colors = GradientColors
)
)
)
我們可以看到Emoji表情,沒有被著色,非常Nice。
我們看一下linearGradient/verticalGradient/radialGradient/sweepGradient
效果對比:
左邊的是linearGradient、右邊的是verticalGradient
左邊的是radialGradient、右邊的是sweepGradient
還有一種內建的Brush,SolidColor,填充指定顏色。
檢視Brush#LinearGradient原始碼發現它繼承自ShaderBrush
kotlin
// androidx.compose.ui.graphics.Brush
class LinearGradient internal constructor(
private val colors: List<Color>,
private val stops: List<Float>? = null,
private val start: Offset,
private val end: Offset,
private val tileMode: TileMode = TileMode.Clamp
) : ShaderBrush()
自定義ShaderBrush,可以修改畫筆大小,那麼我們也來整一個,用於下面的鎢絲燈的照亮效果,剛剛上面還介紹了到一個gradient
符合我們的要求,radialGradient,更多的原始碼細節,這裡就不做深入介紹,夜深了哈哈哈。
我們接下來需要初始化一個ShaderBrush
kotlin
object : ShaderBrush() {
override fun createShader(size: Size): Shader {
return RadialGradientShader(
center = ...,
radius = ...,
colors = ...
)
}
...
}
三、實現照亮文字
剛剛上面初始化了一個ShaderBrush,我們照亮文字內容,文字內容不可能只有一屏對吧,肯定需要支援滑動文字,那要怎麼做呢?
我想肯定有掘友知道了,我們可以用Modifier的verticalScroll修飾符,記錄滾動狀態ScrollState,然後設定到RadialGradientShader的center
裡面。
我們這裡的文字內容引用了:三國演義的第一章內容,我們同樣需要上一篇文章的RopHandleState
kotlin
private fun ComposeText(state: RopeHandleState) {
Text(
text = sanguoString,
modifier = Modifier
.fillMaxSize()
.padding(16.dp)
.verticalScroll(state.scrollState),
style = LocalTextStyle.current.merge(
TextStyle(
fontSize = 18.sp,
brush = state.lightContentBrush
)
)
)
}
這裡我們用到了TextStyle#Brush的API,同時也添加了滾動修飾符,因為我們需要上下滑動文字,保證“鎢絲燈”能照亮
我們的文字內容。
我們在RopHandleState裡面初始化ScrollState
```kotlin val scrollState = ScrollState(0)
private val scrollOffset by derivedStateOf { // 這裡增加Y軸的距離 Offset(size.width / 2F, scrollState.value.toFloat() + size.width * 0.2F) } ``` 可以滾動,我們需要把滾動的距離同步給我們的ShaderBrush
```kotlin // isOpen == true,鎢絲燈亮了需要初始化ShaderBrush object : ShaderBrush() { override fun createShader(size: Size): Shader { lastScrollOffset = Offset(size.width/2F, scrollOffset.y) return RadialGradientShader( center = lastScrollOffset!!, radius = size.minDimension, colors = listOf(Color.Yellow, Color(0xff85733a), Color.DarkGray) ) } override fun equals(other: Any?): Boolean { return lastScrollOffset?.y == scrollOffset.y } }
// isOpen == false,鎢絲燈滅了 SolidColor(Color.DarkGray) ``` 根據“鎢絲燈”的狀態,返回不同的Brush:
kotlin
val lightContentBrush by derivedStateOf {
if(isOpen) {
object : ShaderBrush() { ... }
} else {
SolidColor(Color.DarkGray)
}
}
這裡需要注意一下,我們在開啟和關閉:鎢絲燈
的時候,需要把lastScrollOffset設定為初始狀態值
kotlin
fun toggle() {
isOpen = !isOpen
lastScrollOffset = Offset.Zero
}
其他相關的程式碼,請參考上一篇文章 Compose回憶童年 - 手拉燈繩-開燈/關燈
我們來看看最終效果吧:
延伸:這裡其實還可通過手指觸控指定範圍區域內高亮哦,有興趣的可以去試試!!
- 鴻蒙ArkUI如何開發跨平臺應用?
- HarmonyOS玩轉ArkUI動效 - 水母動畫
- Compose挑燈夜看 - 照亮手機螢幕裡面的書本內容
- 順手修復了Jetpack Compose官方文件中的一個多點觸控示例的Bug
- 正確實踐Jetpack SplashScreen API —— 在所有Android系統上使用總結,內含原理分析
- Jetpack Compose處理“導航欄、狀態列、鍵盤” 影響內容顯示的問題集錦
- 閒聊Android懸浮的“系統文字選擇選單”和“ActionMode解析”——附上原理分析
- Jetpack Compose實現bringToFront功能——附上原理分析
- Android跨程序傳大圖思考及實現——附上原理分析