Android?Compose狀態(tài)改變動(dòng)畫animateXxxAsState使用詳解
前言
上一篇文章我們探索了 Compose 中屬性動(dòng)畫的使用,發(fā)現(xiàn)屬性動(dòng)畫確實(shí)是可以在 Compose 中使用的,雖然使用方式跟傳統(tǒng) Android 開發(fā)中有所區(qū)別,但也不難用,甚至對(duì)于已經(jīng)熟悉了屬性動(dòng)畫的我們來說學(xué)習(xí)成本更低,那么為什么 Compose 又要單獨(dú)搞一套 動(dòng)畫 Api 呢?為了搞清楚這個(gè)問題,首先我們得先學(xué)會(huì) Compose 動(dòng)畫的使用。
實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn),我們將從這一篇開始一步步深入學(xué)習(xí) Compose 動(dòng)畫的使用,看看它到底好不好用。本篇將首先從animateXxxAsState
這一組動(dòng)畫 Api 開始進(jìn)入 Compose 的動(dòng)畫世界。
animateXxxAsState
在 Compose 中提供了一系列動(dòng)畫 API,其中有一類 API 跟屬性動(dòng)畫非常類似,它就是 animateXxxAsState
,我翻譯成狀態(tài)改變動(dòng)畫,其中 Xxx
對(duì)應(yīng)的是 Dp
、Float
、Int
、Size
、Offset
、Rect
、IntOffset
、IntSize
、Color
等數(shù)據(jù)類型,即當(dāng)狀態(tài)改變時(shí)觸發(fā)對(duì)應(yīng)數(shù)據(jù)類型的值的發(fā)生改變,從而執(zhí)行數(shù)據(jù)從當(dāng)前值到目標(biāo)值變化的動(dòng)畫。
對(duì)應(yīng) Api 如圖:
接下來就看看這些 Api 到底是如何使用的。
基礎(chǔ)使用
我們首先以 animateDpAsState
為例來看一下 animateXxxAsState
動(dòng)畫到底如何使用。
Dp
是 Compose 提供的一個(gè)封裝數(shù)據(jù)類型,作用跟在傳統(tǒng) Android 開發(fā)中 xml 使用的 dp
單位是一樣的,是與屏幕像素密度相關(guān)的抽象單位。Compose 中為其提供了基礎(chǔ)數(shù)據(jù)類型的擴(kuò)展,可以直接使用數(shù)值.dp
進(jìn)行使用,如:10.dp
、12.5.dp
等。
在 Compose 中跟長度相關(guān)的參數(shù)類型基本上都是 Dp
,如寬高、圓角、間距等等。
animateDpAsState
的定義如下:
fun animateDpAsState( targetValue: Dp, animationSpec: AnimationSpec<Dp> = dpDefaultSpring, finishedListener: ((Dp) -> Unit)? = null ): State<Dp>
參數(shù)說明:
- targetValue:目標(biāo)值
- animationSpec:動(dòng)畫規(guī)格
- finishedListener:動(dòng)畫完成監(jiān)聽
返回值是一個(gè) State
對(duì)象,即當(dāng)其內(nèi)部 value 值發(fā)生改變時(shí)會(huì)觸發(fā) Compose 的重組,從而刷新界面。
前面說了 animateXxxAsState
跟屬性動(dòng)畫類似,但是好像不對(duì)呀,這里參數(shù)只有一個(gè) targetValue
即目標(biāo)值,熟悉屬性動(dòng)畫的都知道,屬性動(dòng)畫的數(shù)值參數(shù)是一個(gè)可變參數(shù),當(dāng)為 1 個(gè)的時(shí)候,初始值為屬性當(dāng)前值,目標(biāo)值為傳入?yún)?shù)值,多個(gè)參數(shù)時(shí)初始值為第一個(gè)參數(shù)值,那這里只有一個(gè) targetValue
參數(shù)是不是也是初始值是從組件中獲取呢?
我們來試試,創(chuàng)建一個(gè) Box 通過改變其左邊距實(shí)現(xiàn)向右移動(dòng)的動(dòng)畫:
val startPadding = animateDpAsState(10.dp) Box(Modifier .padding(start = startPadding.value, top = 10.dp) .size(100.dp, 100.dp) .background(Color.Blue) )
因?yàn)樾枰獙?duì)左邊距進(jìn)行改變,所以將 padding 的 start 提取為 startPadding 變量,如上面的代碼,但是這樣的話那初始值就是 animateDpAsState
傳入的值,也就是這里的 10.dp ,先運(yùn)行一下看看是不是這樣:
運(yùn)行效果確實(shí)是這樣,那怎么實(shí)現(xiàn)動(dòng)畫效果呢?是修改 startPadding 的值么?我們給 Box 添加一個(gè)點(diǎn)擊事件修改 startPadding 的值看看:
val startPadding = animateDpAsState(10.dp) Box(Modifier .padding(start = startPadding.value, top = 10.dp) .size(100.dp, 100.dp) .background(Color.Blue) // 添加點(diǎn)擊事件 .clickable { // 修改值 報(bào)錯(cuò) startPadding.value = 100.dp } )
這樣寫編輯器直接報(bào)錯(cuò)了,錯(cuò)誤信息如下:
說 val 變量不能重新賦值,是因?yàn)?startPadding 變量定義成了 val 所以不能修改么?并不是,因?yàn)槲覀冎匦沦x值的不是 startPadding 變量,而是其內(nèi)部的 value,而 startPadding 是 State 類型,State 內(nèi)部的 value 是 val 的,定義如下:
interface State<out T> { val value: T }
所以并不能通過重新賦值修改 animateDpAsState
創(chuàng)建的 State 的 value 值,那么怎么修改這個(gè)值讓其產(chǎn)生動(dòng)畫呢?
前面說了 animateXxxAsState 是依賴狀態(tài)改變而產(chǎn)生值的變化,所以實(shí)際上我們這里還需要定義一個(gè)額外的狀態(tài)變量,targetValue 參數(shù)根據(jù)這個(gè)狀態(tài)傳入不同的值,修改上面代碼如下:
@Composable fun DpAnimationBox(){ // 是否移動(dòng)到右邊 var moveToRight by remember { mutableStateOf(false) } //根據(jù) moveToRight 變量傳入?yún)?shù),true 代表在右邊則傳入 100.dp,false 在左邊則傳入 10.dp val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) Box(Modifier .padding(start = startPadding.value, top = 10.dp) .size(100.dp, 100.dp) .background(Color.Blue) .clickable { // 改變 moveToRight 狀態(tài),這里直接取反 moveToRight = !moveToRight } ) }
修改點(diǎn)如下:
- 使用 mutableStateOf 創(chuàng)建 moveToRight 變量,內(nèi)部值為 Boolean 類型,即 MutableState,因?yàn)槭窃?Compose 函數(shù)中使用,需要用 remember 函數(shù)包裹,防止重組時(shí)重復(fù)創(chuàng)建
- 修改 animateDpAsState 傳入?yún)?shù)的固定值為根據(jù) moveToRight 傳入,即
if (moveToRight) 100.dp else 10.dp
- 修改點(diǎn)擊事件處理,修改 moveToRight 的值
運(yùn)行看一下效果:
終于有效果了。所以實(shí)際是根據(jù) moveToRight 的值改變導(dǎo)致傳入 animateDpAsState 的 targetValue 參數(shù)的值發(fā)生改變,而動(dòng)畫執(zhí)行的就是之前舊的值到當(dāng)前設(shè)置最新值的動(dòng)畫效果。
上面的 moveToRight 是 MutableState 類型, 內(nèi)部的 value 是 Boolean 類型,那是不是只能是 Boolean 類型呢,當(dāng)然不是,可以是任何類型,只要在傳入 animateDpAsState 的參數(shù)值時(shí)根據(jù)這個(gè)類型的值進(jìn)行自定義條件判斷傳入不同的數(shù)據(jù)即可,比如定義一個(gè)枚舉類型,根據(jù)不同類型傳入不同的參數(shù),如下:
enum class CustomState{ STATE1, STATE2, STATE3, } var customState by remember { mutableStateOf(CustomState.STATE1) } val paddingValue = when(customState){ CustomState.STATE1 -> 0.dp CustomState.STATE2 -> 100.dp CustomState.STATE3 -> 200.dp } val startPadding = animateDpAsState(paddingValue)
甚至你可以直接創(chuàng)建一個(gè)跟動(dòng)畫值相同的數(shù)據(jù)類型,比如這里可以直接創(chuàng)建一個(gè) Dp 類型的狀態(tài)變量,然后在點(diǎn)擊時(shí)直接改變其值來驅(qū)動(dòng)動(dòng)畫執(zhí)行,如下:
@Composable fun DpAnimationBox(){ // 動(dòng)畫目標(biāo)值 var startPaddingValue by remember { mutableStateOf(10.dp) } // 蔣其設(shè)置給 animateDpAsState val startPadding = animateDpAsState(startPaddingValue) Box(Modifier .padding(start = startPadding.value, top = 10.dp) .size(100.dp) .background(Color.Blue) .clickable { // 改變動(dòng)畫目標(biāo)值 if(startPaddingValue == 10.dp){ startPaddingValue = 100.dp }else{ startPaddingValue = 10.dp } } ) }
上面代碼同樣能實(shí)現(xiàn)跟之前一樣的效果。使用還是相當(dāng)靈活的,開發(fā)中可以根據(jù)實(shí)際的需求定義不同的狀態(tài)來完成我們想要的動(dòng)畫效果。
動(dòng)畫監(jiān)聽
animateXxxAsState
提供了動(dòng)畫完成時(shí)的監(jiān)聽 finishedListener
,可以通過監(jiān)聽動(dòng)畫完成進(jìn)行自定義的業(yè)務(wù)處理,比如修改界面的顯示狀態(tài)或者開啟下一個(gè)動(dòng)畫等。
比如 animateDpAsState
的finishedListener
定義如下:
(Dp) -> Unit
有一個(gè) Dp 類型的參數(shù),即動(dòng)畫完成時(shí)的目標(biāo)值,使用如下:
val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) { //TODO: do something }
比如我們想在上面的動(dòng)畫結(jié)束時(shí)再讓方塊移動(dòng)回去,那我們可以這么寫:
val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) { if(it == 100.dp){ moveToRight = false } }
效果如下:
或者我們想讓這個(gè)方塊往返重復(fù)執(zhí)行,可以這么寫:
val startPadding = animateDpAsState(if (moveToRight) 100.dp else 10.dp) { moveToRight = !moveToRight }
效果如下:
通過對(duì) animateXxxAsState
動(dòng)畫的監(jiān)聽我們可以實(shí)現(xiàn)界面狀態(tài)的刷新或進(jìn)行動(dòng)畫的組合等自定義操作。
使用示例
前面講了 animateDpAsState
動(dòng)畫的使用,其他 animateXxxAsState
api 的使用基本一樣,只是動(dòng)畫作用的數(shù)據(jù)類型不一樣,下面將通過一個(gè)個(gè)簡單示例來看看其他幾個(gè) api 的使用。
animateFloatAsState
animateFloatAsState
作用于 Float 類型數(shù)據(jù)的動(dòng)畫,比如 alpha 值,通過改變控件的 alpha 值可實(shí)現(xiàn)元素的顯示與隱藏,使用示例如下:
@Composable fun FloatAnimationBox() { var show by remember { mutableStateOf(true) } val alpha by animateFloatAsState(if (show) 1f else 0f) Box(Modifier .padding(10.dp) .size(100.dp) .alpha(alpha) .background(Color.Blue) .clickable { show = !show } ) }
動(dòng)畫效果:
animateIntAsState
animateIntAsState
作用于 Int 數(shù)據(jù)類型,上面的 animateDpAsState
實(shí)現(xiàn)的動(dòng)畫也可以使用 animateIntAsState
實(shí)現(xiàn),如下:
@Composable fun IntAnimationBox() { var moveToRight by remember { mutableStateOf(false) } val startPadding by animateIntAsState(if (moveToRight) 100 else 10) Box(Modifier .padding(start = startPadding.dp, top = 10.dp) .size(100.dp) .background(Color.Blue) .clickable { moveToRight = !moveToRight } ) }
效果跟使用 animateDpAsState
實(shí)現(xiàn)的一樣:
animateColorAsState
animateColorAsState
是作用于 Color 上,可實(shí)現(xiàn)顏色的過渡動(dòng)畫,比如將上面的方塊顏色從藍(lán)色變?yōu)榧t色,代碼如下:
@Composable fun ColorAnimationBox() { var toRed by remember { mutableStateOf(false) } val color by animateColorAsState(if (toRed) Color.Red else Color.Blue) Box(Modifier .padding(10.dp) .size(100.dp) .background(color) .clickable { toRed = !toRed } ) }
效果如下:
animateSizeAsState/animateIntSizeAsState
animateSizeAsState
作用于 Size 上,看到這個(gè)我們一下就想到了用于控件的 size 上,比如上面的 Modifier.size()
上,但實(shí)際上 Modifier.size()
的參數(shù)并不是 Size 類型,而是 Dp 類型或者 DpSize
,而 DpSize 并不是 Size 的子類,所以不能直接將 Size 類型的數(shù)據(jù)直接傳入 Modifier.size()
中,而是需要轉(zhuǎn)換一下:
@Composable fun SizeAnimationBox() { var changeSize by remember { mutableStateOf(false) } // 定義 Size 動(dòng)畫 val size by animateSizeAsState(if (changeSize) Size(200f, 50f) else Size(100f, 100f)) Box(Modifier .padding(10.dp) // 設(shè)置 Size 值 .size(size.width.dp, size.height.dp) .background(Color.Blue) .clickable { changeSize = !changeSize } ) }
效果如下:
animateIntSizeAsState
跟 animateSizeAsState
幾乎一樣,只是它作用于 IntSize
,跟 Size 的唯一區(qū)別就是參數(shù)是 Int 類型而不是 Float 類型,如下:
val size by animateIntSizeAsState(if (changeSize) IntSize(200, 50) else IntSize(100, 100))
animateOffsetAsState/animateIntOffsetAsState
animateOffsetAsState
作用于 Offset 類型數(shù)據(jù),用于控制偏移量,同樣的它不能直接用于 Modifier.offset()
上,因?yàn)?Modifier.offset()
接收的也是 Dp 類型參數(shù),所以也需要進(jìn)行轉(zhuǎn)換,如下:
@Composable fun OffsetAnimationBox() { var changeOffset by remember { mutableStateOf(false) } // 定義 offset 動(dòng)畫 val offset by animateOffsetAsState(if (changeOffset) Offset(100f, 100f) else Offset(0f, 0f)) Box(Modifier // 設(shè)置 offset 數(shù)值 .offset(offset.x.dp, offset.y.dp) .padding(10.dp) .size(100.dp) .background(Color.Blue) .clickable { changeOffset = !changeOffset } ) }
效果如下:
animateIntOffsetAsState
則作用于 IntOffset
類型數(shù)據(jù),使用方法與上面一致,只是將 Float 類型換成 Int 類型:
val intOffset by animateIntOffsetAsState(if (changeOffset) IntOffset(100, 100) else IntOffset(0, 0))
Modifier.offset()
提供了一個(gè)返回 IntOffset 的函數(shù)參數(shù),可以如下使用:
Modifier.offset { intOffset }
animateRectAsState
animateRectAsState
作用于 Rect
數(shù)據(jù),即可以同時(shí)控制位置和大小,通過 animateRectAsState
可實(shí)現(xiàn)上面方塊的位置和大小變化的動(dòng)畫,使用如下:
@Composable fun RectAnimationBox() { var changeRect by remember { mutableStateOf(false) } // 定義 rect val rect by animateRectAsState(if (changeRect) Rect(100f, 100f, 310f, 150f) else Rect(10f, 10f, 110f, 110f)) Box(Modifier // 設(shè)置位置偏移 .offset(rect.left.dp, rect.top.dp) // 設(shè)置大小 .size(rect.width.dp, rect.height.dp) .background(Color.Blue) .clickable { changeRect = !changeRect } ) }
效果如下:
實(shí)戰(zhàn)
上面講了 animateXxxAsState
動(dòng)畫 api 的基本使用,下面就用這些 api 來完成一個(gè)實(shí)戰(zhàn)效果,還是上一篇《Compose 中屬性動(dòng)畫的使用》的效果:
前面說了animateXxxAsState
是依賴于狀態(tài)的動(dòng)畫,分析上面的動(dòng)畫一共存在 4 個(gè)狀態(tài):
- 默認(rèn)狀態(tài):顯示藍(lán)色矩形按鈕,文字為 Upload
- 開始上傳狀態(tài):按鈕變?yōu)閳A形且中間為白色,邊框?yàn)榛疑?,文字消?/li>
- 上傳中狀態(tài):邊框根據(jù)進(jìn)度變?yōu)樗{(lán)色
- 上傳完成狀態(tài):按鈕從圓形回到圓角矩形,且顏色變?yōu)榧t色,文字變?yōu)?Success
實(shí)現(xiàn)原理如下:
首先通過一個(gè)枚舉定義上述四種狀態(tài):
enum class UploadState { Normal, Start, Uploading, Success }
然后實(shí)現(xiàn)默認(rèn)狀態(tài)的界面展示:
@Composable fun UploadAnimation() { val originWidth = 180.dp val circleSize = 48.dp var uploadState by remember { mutableStateOf(UploadState.Normal) } var text by remember { mutableStateOf("Upload") } val textAlpha by animateFloatAsState(1f) val backgroundColor by animateColorAsState(Color.Blue) val boxWidth by animateDpAsState(originWidth) val progressAlpha by animateFloatAsState(0f) val progress by animateIntAsState(0) // 界面布局 Box( modifier = Modifier .padding(start = 10.dp, top = 10.dp) .width(originWidth), contentAlignment = Alignment.Center ) { // 按鈕 Box( modifier = Modifier .clip(RoundedCornerShape(circleSize / 2)) .background(backgroundColor) .size(boxWidth, circleSize) .clickable { // 點(diǎn)擊時(shí)修改狀態(tài)為開始上傳 uploadState = UploadState.Start }, contentAlignment = Alignment.Center, ) { // 進(jìn)度 Box( modifier = Modifier.size(circleSize).clip(ArcShape(progress)) .alpha(progressAlpha).background(Color.Blue) ) // 白色蒙版 Box( modifier = Modifier.size(40.dp).clip(RoundedCornerShape(20.dp)) .alpha(progressAlpha).background(Color.White) ) // 文字 Text(text, color = Color.White, modifier = Modifier.alpha(textAlpha)) } } }
然后根據(jù)上傳按鈕的狀態(tài)定義不同狀態(tài)時(shí)的數(shù)據(jù)值:
var textAlphaValue = 1f var backgroundColorValue = Color.Blue var boxWidthValue = originWidth var progressAlphaValue = 0f var progressValue = 0 when (uploadState) { // 默認(rèn)狀態(tài)不處理 UploadState.Normal -> {} // 開始上傳 UploadState.Start -> { // 文字透明度變?yōu)? textAlphaValue = 0f // 按鈕背景顏色變?yōu)榛疑? backgroundColorValue = Color.Gray // 按鈕寬度變?yōu)閳A的寬度 boxWidthValue = circleSize // 中間進(jìn)度的透明度變?yōu)?1 progressAlphaValue = 1f } // 上傳中狀態(tài) UploadState.Uploading -> { textAlphaValue = 0f backgroundColorValue = Color.Gray boxWidthValue = circleSize progressAlphaValue = 1f // 進(jìn)度值變?yōu)?100 progressValue = 100 } // 上傳完成 UploadState.Success -> { // 文字透明度變?yōu)?1 textAlphaValue = 1f // 顏色變?yōu)榧t色 backgroundColorValue = Color.Red // 按鈕寬度變化默認(rèn)時(shí)的原始寬度 boxWidthValue = originWidth // 進(jìn)度透明度變?yōu)?0f progressAlphaValue = 0f } } val textAlpha by animateFloatAsState(textAlphaValue) val backgroundColor by animateColorAsState(backgroundColorValue) val boxWidth by animateDpAsState(boxWidthValue) val progressAlpha by animateFloatAsState(progressAlphaValue) val progress by animateIntAsState(progressValue)
此時(shí)運(yùn)行后點(diǎn)擊按鈕效果如下:
點(diǎn)擊后只有開始上傳的動(dòng)畫,沒有后續(xù)的動(dòng)畫效果,這是因?yàn)槲覀冊邳c(diǎn)擊的時(shí)候只是將狀態(tài)變?yōu)榱?UploadState.Start 而沒有進(jìn)行后續(xù)狀態(tài)的改變,所以需要監(jiān)聽動(dòng)畫完成然后繼續(xù)改變按鈕的狀態(tài)來實(shí)現(xiàn)完整的動(dòng)畫效果,代碼修改如下:
val boxWidth by animateDpAsState(boxWidthValue){ // 按鈕寬度變化完成監(jiān)聽,當(dāng)狀態(tài)為 Start 則修改為 Uploading if(uploadState == UploadState.Start){ uploadState = UploadState.Uploading } } val progress by animateIntAsState(progressValue){ // 進(jìn)度完成監(jiān)聽,當(dāng)狀態(tài)為 Uploading 則修改為 Success if(uploadState == UploadState.Uploading){ uploadState = UploadState.Success // 文字內(nèi)容修改為 Success text = "Success" } }
分別給按鈕寬度變化動(dòng)畫和進(jìn)度動(dòng)畫進(jìn)行監(jiān)聽并修改其狀態(tài),這樣就將整個(gè)動(dòng)畫串聯(lián)起來了,最終效果如下:
最后
關(guān)于 animateXxxAsState
的基本使用就講得差不多了,并通過一系列 api 完成了上一篇使用屬性動(dòng)畫實(shí)現(xiàn)的效果,細(xì)心的同學(xué)會(huì)發(fā)現(xiàn)關(guān)于 animateXxxAsState
其實(shí)還有兩個(gè)知識(shí)點(diǎn)是沒有介紹到的:
animateXxxAsState
還有一個(gè) apianimateValueAsState
animateXxxAsState
的參數(shù)animationSpec
參數(shù)
其中 animateValueAsState
是 animateXxxAsState
的底層 api,上面介紹的一系列 animateXxxAsState
最終都是調(diào)用 animateValueAsState
來實(shí)現(xiàn),關(guān)于 animateValueAsState
我們將在下一篇進(jìn)行詳細(xì)介紹。animationSpec
是對(duì)動(dòng)畫進(jìn)行更詳細(xì)的配置,比如動(dòng)畫的時(shí)間、速度曲線等,將在后續(xù)文章中詳細(xì)介紹
以上就是Android Compose狀態(tài)改變動(dòng)畫animateXxxAsState使用詳解的詳細(xì)內(nèi)容,更多關(guān)于Android Compose狀態(tài)改變動(dòng)畫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android中Notification 提示對(duì)話框
Notification,俗稱通知,是一種具有全局效果的通知,它展示在屏幕的頂端,首先會(huì)表現(xiàn)為一個(gè)圖標(biāo)的形式,當(dāng)用戶向下滑動(dòng)的時(shí)候,展示出通知具體的內(nèi)容2016-01-01Android獲取所在時(shí)區(qū)時(shí)間的兩種方式
Android獲取所在時(shí)區(qū)正確時(shí)間的方式有兩種,通過wifi獲取時(shí)間和通過通過GPS獲取時(shí)間這兩種方式,文中通過代碼示例給大家的介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04基于Flutter實(shí)現(xiàn)圖片選擇和圖片上傳
Flutter?的圖片選擇插件很多,包括了官方的?image_picker,multi_image_picker(基于2.0出了?multi_image_picker2)等等。本文將利用這些插件實(shí)現(xiàn)圖片選擇和圖片上傳,需要的可以參考一下2022-03-03Android編程實(shí)現(xiàn)設(shè)置TabHost當(dāng)中字體的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)設(shè)置TabHost當(dāng)中字體的方法,涉及Android針對(duì)TabHost屬性操作的相關(guān)技巧,非常簡單實(shí)用,需要的朋友可以參考下2015-12-12Android EditText監(jiān)聽回車鍵并處理兩次回調(diào)問題
這篇文章主要介紹了Android EditText監(jiān)聽回車鍵并處理兩次回調(diào)問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08Android?ViewStub使用方法學(xué)習(xí)
這篇文章主要為大家介紹了Android?ViewStub使用方法學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11Android編程判斷當(dāng)前應(yīng)用是否在后臺(tái)運(yùn)行的方法示例
這篇文章主要介紹了Android編程判斷當(dāng)前應(yīng)用是否在后臺(tái)運(yùn)行的方法,涉及Android針對(duì)當(dāng)前程序運(yùn)行狀態(tài)相關(guān)屬性操作與判定技巧,需要的朋友可以參考下2018-03-03Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了Android 實(shí)現(xiàn)定時(shí)器的四種方式總結(jié)及實(shí)現(xiàn)實(shí)例的相關(guān)資料,這里對(duì)定時(shí)器進(jìn)行詳解,并附實(shí)例代碼,需要的朋友可以參考下2016-12-12