<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文帶你了解Android最新 Jetpack Compose UI 框架

          共 6019字,需瀏覽 13分鐘

           ·

          2021-02-02 23:43

          轉(zhuǎn)自:掘金?- Andoter

          Jetpack Compose?是用于構(gòu)建原生界面的新款?Android?工具包。它可簡化并加快?Android?的?UI?開發(fā)工作。使用更少的代碼、強大的工具和直觀的?Kotlin API,快速構(gòu)建?App?的?UI。目前Jetpack Compose?為?Alpha?版。所以需要在?Android Studio?的?Canary?版本才能體驗。

          1. 創(chuàng)建?Jetpack Compose?項目

          在?Android Studio Canary?版本中已經(jīng)提供了?Compose?的模板,在創(chuàng)建項目時選擇?Empty Compose Activity?模板即可。

          img

          至此,就完成一個?Compose?項目的創(chuàng)建。除此之外,我們也可以選擇導入?Jetpack Compose?示例應用。

          2. Compose 函數(shù)使用

          Compose?是一種以函數(shù)為依托的聲明式?UI?構(gòu)建方式。比如在?MainActivity.kt?中顯示一個文本。

          class?MainActivity?:?AppCompatActivity()?{
          ????override?fun?onCreate(savedInstanceState:?Bundle?)?{
          ????????super.onCreate(savedInstanceState)
          ????????setContent?{
          ????????????Text("Hello?Compose!")
          ????????}
          ????}
          }
          hello_compose

          這個與使用?XML?布局的方式差別很大,setContent?塊定義了?Activity?的布局。我們不使用?XML?文件來定義布局內(nèi)容,而是調(diào)用一個?Compose?函數(shù),比如上面的?Text?函數(shù)。然后?Jetpack Compose?使用自定義?Kotlin?編譯器插件將這些?Compose?函數(shù)轉(zhuǎn)換為應用的界面元素。

          2.1?Compose?函數(shù)

          Jetpack Compose?是圍繞?Compose?函數(shù)構(gòu)建的,在開發(fā)時只需描述應用界面的樣式布局和數(shù)據(jù)依賴關(guān)系,而不必關(guān)注界面的構(gòu)建過程。給一個函數(shù)添加?@Composable?注解即創(chuàng)建了一個 Compose 函數(shù)。注意,Compose?函數(shù)只能在其他?Compose?函數(shù)的范圍內(nèi)調(diào)用。下面我們將上面示例中的?Text?移動到自定義的?Compose?函數(shù)中。

          class MainActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
          setContent {
          HelloCompose()
          }
          }

          @Composable
          fun HelloCompose() {
          Text("Hello Compose!")
          }
          }
          2.3 設(shè)置點擊監(jiān)聽

          除了使用?Text?函數(shù),還有其它的基礎(chǔ)函數(shù)供我們使用,比如?ButtonImage?等。那么如何給?UI?控件設(shè)置點擊監(jiān)聽呢?在?Compose?框架中提供了兩種方式:

          • 對于類似?Button?函數(shù)的這種,提供了?onClick?函數(shù)式接口供外部設(shè)置點擊監(jiān)聽;
          • 對于類似?Text?函數(shù)這種,沒有提供顯式接口設(shè)置的,通過?Modifier?類設(shè)置點擊監(jiān)聽;

          Button?函數(shù)設(shè)置點擊事件

          @Composable
          fun?TextButton()?{
          ????Button(
          ????????onClick?=?{
          ????????????Log.d("Andoter",?this.javaClass.name)
          ????????????Toast.makeText(this@MainActivity,?"Button?點擊",?Toast.LENGTH_SHORT).show()
          ????????}
          ????)?{
          ????????Text(text?=?"Hello?Compose!",?color?=?Color.Red)
          ????}
          }

          通過設(shè)置?onClick?函數(shù)即可實現(xiàn)點擊實現(xiàn),注意?Button?函數(shù)本身沒有設(shè)置文本內(nèi)容,需要通過?Text?函數(shù)設(shè)置顯示文本內(nèi)容。

          Text?函數(shù)設(shè)置點擊事件

          @Composable
          fun?ClickedText()?{
          ????val?modifier?=?Modifier.clickable(onClick?=?{
          ????????Log.d("Andoter",?this.javaClass.name)
          ????????Toast.makeText(this@MainActivity,?"Button?點擊",?Toast.LENGTH_SHORT).show()
          ????})

          ????Text(text?=?"Hello?Compose!",modifier?=?modifier.padding(10.dp))
          }

          通過?Modifier.clickable?的方式實現(xiàn)設(shè)置點擊事件。Modifier?類不僅能夠設(shè)置點擊事件,還能夠設(shè)置控件的布局屬性。

          • clickable()?:設(shè)置點擊監(jiān)聽
          • padding()?:在元素周圍留出空間
          • fillMaxWidth()?:使可組合項填充其父項給它的最大寬度
          • preferredSize()?:指定元素的首選寬度和高度
          2.4 預覽

          在?Compose?框架中為?Compose?函數(shù)提供預覽能力,通過給?Compose?函數(shù)添加?@Preview?注解即可進行預覽。在實際的開發(fā)中,預覽函數(shù)不要發(fā)布到線上,所以最佳做法是單獨創(chuàng)建不會被應用調(diào)用的預覽函數(shù)用于查看實際效果,專門的預覽函數(shù)可以提高性能,并且有利于以后更輕松地設(shè)置多個預覽。

          (動圖圖片過大,無法上傳,截圖處理)

          3. 布局

          在?Jetpack Compose?中一切的元素都是圍繞?Compose?函數(shù)展開,所以布局也是通過對應的內(nèi)置?Compose?函數(shù)實現(xiàn)。

          3.1?Column?和?Row

          二者的特點:

          • Column:使元素按照豎直方向排列;
          • Row:使元素按照水平方向排列;
          • Stack:將一個元素放在另一個元素上。

          這里我們以?Column?函數(shù)作為示例。

          @Preview
          @Composable
          fun?MultiText()?{
          ????Text(text?=?"Hello?Compose!")
          ????Text("Ant 學習 Compose!")
          }


          @Preview
          @Composable
          fun?ColumnText()?{
          ????Column?{
          ????????Text(text?=?"Hello?Compose!")
          ????????Text("Ant 學習 Compose!")
          ????}
          }

          通過?Column?可將組件按照豎直方向排列,預覽效果對比:

          column
          3.2?ScrollableRow?和?ScrollableColumn

          使用?ScrollableRow?或?ScrollableColumn?可使?Row?或?Column?內(nèi)的元素滾動。

          @Composable
          fun?ProductList()?{
          ????ScrollableColumn(Modifier.fillMaxSize())?{
          ????????listOf("Ant",?"Andoter",?"小偉").forEach?{?value?->
          ????????????ProductDetailView(value)
          ????????}
          ????}
          }

          @Composable
          fun?ProductDetailView(text:?String)?{
          ????val?image?=?imageResource(id?=?R.drawable.header)
          ????Column(modifier?=?Modifier.padding(16.dp))?{
          ????????val?imageModifier?=?Modifier
          ????????????.preferredHeight(180.dp)
          ????????????.clip(shape?=?RoundedCornerShape(5.dp))
          ????????????.fillMaxWidth()
          ????????????.clickable(onClick?=?{
          ????????????????Log.d("Ant",?"click");
          ????????????})
          ????????Image(image,?modifier?=?imageModifier,?contentScale?=?ContentScale.Crop)
          ????????Spacer(modifier?=?Modifier.preferredHeight(16.dp))
          ????????Text("Hello?Compose!")
          ????}
          }
          scroll_column

          4.?Compose?界面結(jié)構(gòu)

          通過上面的介紹,對?Compose?有了一個初步的認識,那么?Compose?函數(shù)如何繪制在屏幕上的呢?以什么樣的形式展示的呢?我們使用?Layout Inspector?工具查看一個?Compose?頁面。

          layer

          通過左側(cè)的布局結(jié)構(gòu)可以發(fā)現(xiàn),Compose?框架中已經(jīng)廢棄原有的View?體系中的控件(TextView、Button、ImageView?等),而是使用?AndroidComposeView(繼承?ViewGroup)、ViewLayerContainer(繼承?ViewGroup)和?ViewLayer(繼承?View) 控件實現(xiàn),其中?ViewLayer?代表每個?View?控件視圖。

          查看?ViewLayer?的調(diào)用關(guān)系,可以得到視圖的生成關(guān)系:LayerWrapper?→?AndroidComposeView?->?ViewLayer。

          5.?Compose?對業(yè)務的影響

          Jetpack Compose?是一個適用于?Android?的新式聲明性界面工具包,同時點擊監(jiān)聽的設(shè)置方式也發(fā)生較大變化,那么對于我來說,最直觀的業(yè)務影響是無法繼續(xù)使用原有的插碼技術(shù)進行點擊事件的采集。這塊需要進行調(diào)研適配。

          上面提到設(shè)置點擊的兩種方式,本質(zhì)上都是通過?Modifier?進行實現(xiàn),來看下面的一個例子。

          @Composable
          fun?ClickedText()?{
          ????val?modifier?=?Modifier.clickable(onClick?=?{
          ????????Log.d("Andoter",?this.javaClass.name)
          ????????Toast.makeText(this@MainActivity,?"Button?點擊",?Toast.LENGTH_SHORT).show()
          ????})

          ????Text(text?=?"Hello?Compose!",?modifier?=?modifier.padding(10.dp))
          }

          通過?Modifier?給一個?Text?設(shè)置點擊監(jiān)聽,在點擊的時候彈出一個?Toast。反編譯看看最后的實現(xiàn)。

          /*?access?modifiers?changed?from:?package-private?*/
          @Metadata(mo23161bv?=?{1,?0,?3},?mo23164k?=?3,?mo23165mv?=?{1,?4,?0})
          /*?compiled?from:?MainActivity.kt?*/
          public?final?class?MainActivity$TextButton$1$1?extends?Lambda?implements?Function0<Unit>?{
          ????private?final?/*?synthetic?*/?MainActivity?$this;

          ????/*?JADX?INFO:?super?call?moved?to?the?top?of?the?method?(can?break?code?semantics)?*/
          ????MainActivity$TextButton$1$1(MainActivity?mainActivity)?{
          ????????super(0);
          ????????this.$this?=?mainActivity;
          ????}

          ????@Override?//?kotlin.jvm.functions.Function0
          ????public?final?void?invoke()?{
          ????????Log.d(LiveLiterals$MainActivityKt.INSTANCE.mo17059x27db7fde(),?this.$this.getClass().getName());
          ????????Toast.makeText(this.$this,?LiveLiterals$MainActivityKt.INSTANCE.mo17064x88044b3e(),?0).show();
          ????}
          }

          Kotlin?經(jīng)過處理最終是轉(zhuǎn)換成一個繼承?Lambda?并實現(xiàn)?Fuction0?接口的類來托管實現(xiàn)點擊監(jiān)聽。這樣我們就可以總結(jié)出?Hook?條件:

          • kotlin.jvm.internal.Lambda?的子類
          • 實現(xiàn)?kotlin.jvm.functions.Function?接口
          • 被?public?和?final?修飾符的?invoke?方法

          盡管?Hook?點找到了,但是目前還無法突破獲取對應的?View,依托?View?讀取的屬性就無法獲取。希望可以一起跟你探討下。

          6. 總結(jié)

          長期以來,Android?視圖層次結(jié)構(gòu)一直可以表示為界面微件樹。界面更新方式是使用?findViewById()?等函數(shù)遍歷樹,這種手動操縱視圖的方式會提高出錯的可能性。在過去的幾年中,移動端已開始轉(zhuǎn)向聲明性界面模型,比如?FlutterSwift UI,所以?Jetpack Compose?框架應該也是后續(xù)發(fā)展的一個方向。

          PS:如果覺得我的分享不錯,歡迎大家隨手點贊、在看。

          大家一起在評論區(qū)聊聊唄~

          瀏覽 82
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  开操网| 性爱网站免费看 | 日韩熟女av | 欧美日韩一 | 国产做爰视频免费播放 |