<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 drawable竟然還能這么寫?

          共 10314字,需瀏覽 21分鐘

           ·

          2021-07-30 19:23

             
          微信改了推動機(jī)制,真愛請星標(biāo)本公號
          公眾號回復(fù)加入BATcoder技術(shù)群BAT

          作者:forJrking

          https://juejin.cn/user/2612095355987191

          前言

          通常我們在res/drawable下面自定義shape和selector來滿足一些UI的設(shè)計,但是由于xml最終轉(zhuǎn)換為drawable需要經(jīng)過IO或反射創(chuàng)建,會有一些性能損耗,另外隨著項目的增大和模塊化等,很多通用的樣式并不能快速復(fù)用,需要合理的項目資源管理規(guī)范才能實施。那么通過代碼直接創(chuàng)建這些drawable,可以在一定程度上降低這些副作用。本篇介紹用kotlin DSL簡潔的語法特性來實現(xiàn)常見的drawable。


          代碼對應(yīng)效果預(yù)覽







          集成和使用

          在項目級的build.gradle文件種添加倉庫Jitpack


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



          添加依賴

          dependencies {        
              implementation 'com.github.forJrking:DrawableDsl:0.0.3’
          }


          拋棄xml創(chuàng)建方式示例(其他參見demo)

          // infix用法用于去掉括號更加簡潔,詳細(xì)后面說明
          image src shapeDrawable {
              //指定shape樣式
              shape(ShapeBuilder.Shape.RECTANGLE)
              //圓角,支持4個角單獨設(shè)置
              corner(20f)
              //solid 顏色
              solid("#ABE2E3")
              //stroke 顏色,邊框dp,虛線設(shè)置
              stroke(R.color.white, 2f5f8f)
          }
          //按鈕點擊樣式
          btn.background = selectorDrawable {
              //默認(rèn)樣式
              normal = shapeDrawable {
                  corner(20f)
                  gradient(90, R.color.F97794, R.color.C623AA2)
              }
              //點擊效果
              pressed = shapeDrawable {
                  corner(20f)
                  solid("#84232323")
              }
          }

          實現(xiàn)思路

          xml如何轉(zhuǎn)換成drawable


          xml變成drawable,通過android.graphics.drawable.DrawableInflater這個類來IO解析標(biāo)簽創(chuàng)建,然后通過解析標(biāo)簽再設(shè)置屬性:


          //標(biāo)簽創(chuàng)建
          private Drawable inflateFromTag(@NonNull String name) {
              switch (name) {
                  case "selector":
                      return new StateListDrawable();
                  case "level-list":
                      return new LevelListDrawable();
                  case "layer-list":
                      return new LayerDrawable();
                  ....
                  case "color":
                      return new ColorDrawable();
                  case "shape":
                      return new GradientDrawable();
                  case "vector":
                      return new VectorDrawable();
                  ...
              }
          }
          //反射創(chuàng)建
          private Drawable inflateFromClass(@NonNull String className) {
              try {
                  Constructor<? extends Drawable> constructor;
                  synchronized (CONSTRUCTOR_MAP) {
                      constructor = CONSTRUCTOR_MAP.get(className);
                      if (constructor == null) {
                          final Class<? extends Drawable> clazz = mClassLoader.loadClass(className).asSubclass(Drawable.class);
                          constructor = clazz.getConstructor();
                          CONSTRUCTOR_MAP.put(className, constructor);
                      }
                  }
                  return constructor.newInstance();
              } catch (NoSuchMethodException e) {
              ...
          }


          代碼實現(xiàn)

          由于創(chuàng)建shape等需要設(shè)置各種屬性來構(gòu)建,比較符合build設(shè)計模式,那我們首先封裝build模式的shapeBuilder,這樣做雖然代碼比起直接使用apply{}要多,但是可以讓純java項目用起來很舒服,其他實現(xiàn)請查看源碼:


          class ShapeBuilder : DrawableBuilder {
              private var mRadius = 0f
              private var mWidth = 0f
              private var mHeight = 0f
              ...
              private var mShape = GradientDrawable.RECTANGLE
              private var mSolidColor = 0

              /**分別設(shè)置四個角的圓角*/
              fun corner(leftTop: Float,rightTop: Float,leftBottom: Float,rightBottom: Float): ShapeBuilder {
                  ....if(dp)dp2px(leftTop) else leftTop
                  return this
              }

              fun solid(@ColorRes colorId: Int): ShapeBuilder {
                  mSolidColor = ContextCompat.getColor(context, colorId)
                  return this
              }
              // 省略其他參數(shù)設(shè)置方法 詳細(xì)代碼查看源碼
              override fun build(): Drawable {
                  val gradientDrawable = GradientDrawable()
                  gradientDrawable = GradientDrawable()
                  gradientDrawable.setColor(mSolidColor)
                  gradientDrawable.shape = mShape
                  ....其他參數(shù)設(shè)置
                  return gradientDrawable
              }    
          }


          把build模式轉(zhuǎn)換為dsl

          理論上所有的build模式都可以輕松轉(zhuǎn)換為dsl寫法:


          inline fun shapeDrawable(builder: ShapeBuilder.() -> Unit): Drawable {
              return ShapeBuilder().also(builder).build()
          }
          //使用方法 
          val drawable = shapeDrawable{
              ...
          }


          函數(shù)去括號

          通過上面封裝已經(jīng)實現(xiàn)了dsl的寫法,通常setBackground可以通過setter簡化,但是我發(fā)現(xiàn)由于有些api設(shè)計還需要加括號,這樣不太kotlin:


          //容易閱讀
          iv1.background = shapeDrawable {
              shape(ShapeBuilder.Shape.RECTANGLE)
              solid("#ABE2E3")
          }
          //多了括號看起來不舒服
          iv2.setImageDrawable(shapeDrawable {
              solid("#84232323")
          })


          怎么去掉括號呢?有2種方式infix函數(shù)(中綴表達(dá))和property setter

          infix函數(shù)特點和規(guī)范


          • Kotlin允許在不使用括號和點號的情況下調(diào)用函數(shù)
          • 必須只有一個參數(shù)
          • 必須是成員函數(shù)或擴(kuò)展函數(shù)
          • 不支持可變參數(shù)和帶默認(rèn)值參數(shù)



              
          /**為所有ImageView添加擴(kuò)展infix函數(shù) 來去掉括號*/
          infix fun ImageView.src(drawable: Drawable?) {
              this.setImageDrawable(drawable)
          }
          //使用如下
          iv2 src shapeDrawable {
              shape(ShapeBuilder.Shape.OVAL)
              solid("#E3ABC2")
          }

          當(dāng)然了代碼是用來閱讀的。個人認(rèn)為如果我們大量使用infix函數(shù),閱讀困難會大大增加,所以建議函數(shù)命名必須可以直擊函數(shù)功能,而且函數(shù)功能簡單且單一。

          property setter方式

          主要使用kotlin可以簡化setter為等號來去括號:

              
          /**擴(kuò)展變量*/
          var ImageView.src: Drawable
              get() 
          drawable
              set(value) 
          {
                  this.setImageDrawable(value)
              }
          //使用如下   
          iv2.src = shapeDrawable {
              shape(ShapeBuilder.Shape.OVAL)
              solid("#E3ABC2")
          }    

          感謝@叮凜凜指點,歡迎大家討論一起學(xué)習(xí),共同進(jìn)步。

          優(yōu)缺點

          優(yōu)點

          • 代碼直接創(chuàng)建比起xml方式可以提升性能
          • dsl方式比起build模式和調(diào)用方法設(shè)置更加簡潔符合kotlin風(fēng)格
          • 通過合適的代碼管理可以復(fù)用這些代碼,比xml管理方便



          缺點

          • 沒有as的預(yù)覽功能,只有通過上機(jī)觀測
          • api還沒有覆蓋所有drawable屬性(例如shape = ring等)

          結(jié)語


          上面把的DrawableDsl基礎(chǔ)用法介紹完了,歡迎大家使用,歡迎提Issues,記得給個star哦。Github鏈接:


          https://github.com/forJrking/DrawableDsl



          ·················END·················

          推薦閱讀

          ? 耗時2年,Android進(jìn)階三部曲第三部《Android進(jìn)階指北》出版!

          ? 『BATcoder』做了多年安卓還沒編譯過源碼?一個視頻帶你玩轉(zhuǎn)!

          ? 鴻蒙來了,拜拜了,Powered by Android!

          ? 重生!進(jìn)階三部曲第一部《Android進(jìn)階之光》第2版 出版!

          BATcoder技術(shù)群,讓一部分人先進(jìn)大廠

          大家,我是劉望舒,騰訊TVP,著有三本技術(shù)暢銷書,連續(xù)四年蟬聯(lián)電子工業(yè)出版社年度優(yōu)秀作者,谷歌開發(fā)者社區(qū)特邀講師。

          前華為技術(shù)專家,現(xiàn)大廠技術(shù)負(fù)責(zé)人。

          想要加入 BATcoder技術(shù)群,公號回復(fù)BAT 即可。

          為了防止失聯(lián),歡迎關(guān)注我的小號


                 
            微信改了推送機(jī)制,真愛請星標(biāo)本公號??
          瀏覽 54
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  日本少妇高潮喷水XXXXXXX | www.日韩黄片 | 超碰97人妻 | 亚洲成人p | 韩国啪啪免费视频 |