91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Dialog按照順序彈窗的優雅寫法是怎樣的

發布時間:2021-09-24 15:15:07 來源:億速云 閱讀:123 作者:柒染 欄目:開發技術

Dialog按照順序彈窗的優雅寫法是怎樣的,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

    我為 Compose 寫了一個波浪效果的進度加載庫,API 的設計上符合 Compose 的開發規范,使用非常簡便。

    1. 使用方式

    在 root 的 build.gradle 中引入 jitpack

    allprojects {
    	repositories {
    		...
    		maven { url 'https://jitpack.io' }
    	}
    }

    在 module 的 build.gradle 中引入 ComposeWaveLoading 的最新版本

    dependencies {
        implementation 'com.github.vitaviva:ComposeWaveLoading:$latest_version'
    }

    2. API 設計思想

    Box {
        WaveLoading (
            progress = 0.5f // 0f ~ 1f
        ) {
            Image(
              painter = painterResource(id = R.drawable.logo_tiktok),
              contentDescription = ""
            )
        }
    }

    傳統的 UI 開發方式中,設計這樣一個波浪控件,一般會使用自定義 View 并將 Image 等作為屬性傳入。 而在 Compose 中,我們讓 WaveLoadingImage 以組合的方式使用,這樣的 API 更加靈活,WaveLoding 的內部可以是 Image,也可以是 Text 亦或是其他 Composable。波浪動畫不拘泥于某一特定 Composable, 任何 Composable 都可以以波浪動畫的形式展現, 通過 Composable 的組合使用,擴大了 “能力” 的覆蓋范圍。

    3. API 參數介紹

    @Composable
    fun WaveLoading(
        modifier: Modifier = Modifier,
        foreDrawType: DrawType = DrawType.DrawImage,
        backDrawType: DrawType = rememberDrawColor(color = Color.LightGray),
        @FloatRange(from = 0.0, to = 1.0) progress: Float = 0f,
        @FloatRange(from = 0.0, to = 1.0) amplitude: Float = defaultAmlitude,
        @FloatRange(from = 0.0, to = 1.0) velocity: Float = defaultVelocity,
        content: @Composable BoxScope.() -> Unit
    ) { ... }

    參數說明如下:

    參數說明
    progress加載進度
    foreDrawType波浪圖的繪制類型: DrawColor 或者 DrawImage
    backDrawType波浪圖的背景繪制
    amplitude波浪的振幅, 0f ~ 1f 表示振幅在整個繪制區域的占比
    velocity波浪移動的速度
    content子Composalble

    接下來重點介紹一下 DrawType

    DrawType

    波浪的進度體現在前景(foreDrawType)和后景(backDrawType)的視覺差,我們可以為前景后景分別指定不同的 DrawType 改變波浪的樣式。

    sealed interface DrawType {
        object None : DrawType
        object DrawImage : DrawType
        data class DrawColor(val color: Color) : DrawType
    }

    如上,DrawType 有三種類型:

    • None: 不進行繪制

    • DrawColor:使用單一顏色繪制

    • DrawImage:按照原樣繪制

    以下面這個 Image 為例, 體會一下不同 DrawType 的組合效果

    indexbackDrawTypeforeDrawType說明
    1DrawImageDrawImage背景灰度,前景原圖
    2DrawColor(Color.LightGray)DrawImage背景單色,前景原圖
    3DrawColor(Color.LightGray)DrawColor(Color.Cyan)背景單色,前景單色
    4NoneDrawColor(Color.Cyan)無背景,前景單色

    注意 backDrawType 設置為 DrawImage 時,會顯示為灰度圖。

    4. 原理淺析

    簡單介紹一下實現原理。為了便于理解,代碼經過簡化處理,完整代碼可以在 github 查看

    這個庫的關鍵是可以將 WaveLoading {...} 內容取出,加以波浪動畫的形式顯示。所以需要將子 Composalbe 轉成 Bitmap 進行后續處理。

    4.1 獲取 Bitmap

    我在 Compose 中沒找到獲取位圖的辦法,所以用了一個 trick 的方式, 通過 Compose 與 Android 原生視圖良好的互操作性,先將子 Composalbe 顯示在 AndroidView 中,然后通過 native 的方式獲取 Bitmap:

    @Composable
    fun WaveLoading (...)
    {
        Box {
     
            var _bitmap by remember {
                mutableStateOf(Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565))
            }
            
            AndroidView(
                factory = { context ->
                    // Creates custom view
                    object : AbstractComposeView(context) {
     
                        @Composable
                        override fun Content() {
                            Box(Modifier.wrapContentSize(){
                                content()
                            }
                        }
     
     
                        override fun dispatchDraw(canvas: Canvas?) {
                            val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
                            val canvas2 = Canvas(source)
                            super.dispatchDraw(canvas2)
                            _bitmap = bmp
                            
                        }
     
                    }
                }
     
            )
     
     
            WaveLoadingInternal(bitmap = _bitmap)
     
        }
    }

    AndroidView 是一個可以繪制 Composable 的原生控件,我們將 WaveLoading 的子 Composable 放在其 Content 中,然后在 dispatchDraw 中繪制時,將內容繪制到我們準備好的 Bitmap 中。

    4.2 繪制波浪線

    我們基于 Compose 的 Canvas 繪制波浪線,波浪線通過 Path 承載 定義 WaveAnim 用來進行波浪線的繪制

    internal data class WaveAnim(
        val duration: Int,
        val offsetX: Float,
        val offsetY: Float,
        val scaleX: Float,
        val scaleY: Float,
    ) {
     
        private val _path = Path()
     
        //繪制波浪線
        internal fun buildWavePath(
            dp: Float,
            width: Float,
            height: Float,
            amplitude: Float,
            progress: Float
        ): Path {
     
            var wave = (scaleY * amplitude).roundToInt() //計算拉伸之后的波幅
     
            _path.reset()
            _path.moveTo(0f, height)
            _path.lineTo(0f, height * (1 - progress))
     
            // 通過正弦曲線繪制波浪
            if (wave > 0) {
                    var x = dp
                    while (x < width) {
                        _path.lineTo(
                            x,
                            height * (1 - progress) - wave / 2f * Math.sin(4.0 * Math.PI * x / width)
                                .toFloat()
                        )
                        x += dp
                    }
            }
                
            _path.lineTo(width, height * (1 - progress))
            _path.lineTo(width, height)
            _path.close()
            return _path
        }
     
    }

    如上,波浪線 Path 通過正弦函數繪制。

    4.3 波浪填充

    有了 Path ,我們還需要填充內容。填充的內容前文已經介紹過,或者是 DrawColor 或者 DrawImage。 繪制 Path 需要定義 Paint

     val forePaint = remember(foreDrawType, bitmap) {
            Paint().apply {
                shader = BitmapShader(
                    when (foreDrawType) {
                        is DrawType.DrawColor -> bitmap.toColor(foreDrawType.color)
                        is DrawType.DrawImage -> bitmap
                        else -> alphaBitmap
                    },
                    Shader.TileMode.CLAMP,
                    Shader.TileMode.CLAMP
                )
            }
        }

    Paint 使用 Shader 著色器繪制 Bitmap, 當 DrawType 只繪制單色時, 對位圖做單值處理:

    /**
     * 位圖單色化
     */
    fun Bitmap.toColor(color: androidx.compose.ui.graphics.Color): Bitmap {
        val bmp = Bitmap.createBitmap(
            width, height, Bitmap.Config.ARGB_8888
        )
        val oldPx = IntArray(width * height) //用來存儲原圖每個像素點的顏色信息
        getPixels(oldPx, 0, width, 0, 0, width, height) //獲取原圖中的像素信息
     
        val newPx = oldPx.map {
            color.copy(Color.alpha(it) / 255f).toArgb()
        }.toTypedArray().toIntArray()
        bmp.setPixels(newPx, 0, width, 0, 0, width, height) //將處理后的像素信息賦給新圖
        return bmp
    }

    4.4 波浪動畫

    最后通過 Compose 動畫讓波浪動起來

    val transition = rememberInfiniteTransition()
     
        val waves = remember(Unit) {
            listOf(
                WaveAnim(waveDuration, 0f, 0f, scaleX, scaleY),
                WaveAnim((waveDuration * 0.75f).roundToInt(), 0f, 0f, scaleX, scaleY),
                WaveAnim((waveDuration * 0.5f).roundToInt(), 0f, 0f, scaleX, scaleY)
            )
        }
     
        val animates :  List<State<Float>> = waves.map { transition.animateOf(duration = it.duration) }

    為了讓波浪更有層次感,我們定義三個 WaveAnim 以 Set 的形式做動畫

    最后,配合 WaveAnim 將波浪的 Path 繪制到 Canvas 即可

    Canvas{
     
            drawIntoCanvas { canvas ->
     
                //繪制后景
                canvas.drawRect(0f, 0f, size.width, size.height, backPaint)
     
     
                //繪制前景
                waves.forEachIndexed { index, wave ->
     
                    canvas.withSave {
     
                        val maxWidth = 2 * scaleX * size.width / velocity.coerceAtLeast(0.1f)
                        val maxHeight = scaleY * size.height
                      
                        canvas.drawPath (
                            wave.buildWavePath(
                                width = maxWidth,
                                height = maxHeight,
                                amplitude = size.height * amplitude,
                                progress = progress
                            ), forePaint
                        )
                    }
     
                }
            }
        }

    看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    防城港市| 宾川县| 崇礼县| 凤山县| 西充县| 福建省| 吉水县| 阳曲县| 酉阳| 万年县| 鸡泽县| 临颍县| 泊头市| 开封县| 巴青县| 海宁市| 曲麻莱县| 金寨县| 黄梅县| 青海省| 句容市| 彰化县| 贵溪市| 高密市| 柯坪县| 玉树县| 日土县| 嘉峪关市| 黄陵县| 台中县| 湄潭县| 浦北县| 胶南市| 桦川县| 呼和浩特市| 舞钢市| 正镶白旗| 元江| 册亨县| 陇南市| 东乌|