Kotlin實戰填坑

話說,怎麼纔算實戰?在此以前我已經使用Kotlin寫過幾個項目了,從最初的一邊看文檔一邊面向QQ羣編程,到如今本身也能夠和衆人侃侃而談Kotlin的基礎語法,那麼問題來了——我爲何如今纔開始叫「Kotlin實戰」呢?由於我以前敲代碼都是規規矩矩沒有任何問題,可是最近在使用一個項目的時候,遇到了很多問題,所以作一個總結,但願能夠幫到其餘人。html

項目簡介

先給你們簡單介紹一下項目的來源:重構UIWidgetRadiusView.爲何要重構呢?由於在使用過程當中以爲這個模塊的功能很強大,可是在使用的過程當中有一些默認屬性不是很熟悉,甚至以爲是bug,因而打算熟悉此此項目並重構並放到本身的項目模板中。可是我在重構過程當中遇到一些困難:java

  • 泛型使用問題
  • 類的繼承問題

泛型使用問題

我對泛型的瞭解,僅限於Java中的泛型方法、泛型類,以爲沒有什麼難度,因而看見代碼直接幹。先看看java代碼是什麼樣的?android

public class RadiusViewDelegate<T extends RadiusViewDelegate> {
    ...
}
複製代碼

soSeay,這個類的聲明確實很簡單,因而我三下五除二的很快寫好了,代碼以下:git

咦?咋不行呢?沒事,我還有一招,javaKotlin代碼,巴拉巴拉魔法變:github

咋這招也不靈呢?不是說好java能夠作的事情,Kotlin也能夠作的嗎?原來童話都是騙人的?編程

童話沒有騙人,是講童話的人騙了你!咱們嘗試修改一下泛型呢?

open class RadiusViewDelegate<T : RadiusViewDelegate<T>>(
    val a: View,
    open val b: Context,
    open val c: AttributeSet?
)
open class B<T : RadiusViewDelegate<T>>(a: View, b: Context, c: AttributeSet?) :RadiusViewDelegate<T >(a,b,c){

}
複製代碼

看來童話確實是存在的,Java能夠乾的活Kotlin照樣能幹!可是還有一個問題,如何聲明B這個對象呢?直接寫確定是不行的,不信的話你能夠試一下,固然,我也能夠給你截一張圖:api

那麼咱們應該怎麼解決呢?不是說好童話是存在的嗎?咱們嘗試一下聲明C繼承B而後使用C這個對象,代碼以下:bash

class C(a: View, b: Context, c: AttributeSet?):B<C>(a, b, c){

}
val b = C(radiusSwitch,this,null)
複製代碼

看來這樣是能夠的,那麼咱們爲何要經過繼承來實現呢?或者,咱們爲何要使用這樣的泛型呢?回答了第二個問題,第一個問題都不是問題了。此處使用泛型的緣由是爲了使子類能夠鏈式調用父類的方法。衆所周知,爲了鏈式調用,咱們能夠對調用的方法增長一個返回值this,這樣就能夠實現鏈式調用了。可是涉及子類繼承呢?子類調用父類的方法返回的是父類,雖然能夠強轉也不會報錯,可是這樣強轉之後的「鏈式調用」還算鏈式調用嗎?話說回來,咱們怎麼經過增長一個泛型實現鏈式調用呢? 咱們在頂層父類增長一個返回this的方法,而後包括子類全部須要返回this的地方都調用這個方法便可。app

open class RadiusViewDelegate<T : RadiusViewDelegate<T>>(
    val a: View,
    open val b: Context,
    open val c: AttributeSet?
){
      fun back(): T {
        return this as T
    }
}
複製代碼

到這裏咱們就解決了爲何使用泛型、怎麼使用泛型,可是咱們尚未認真去了解一下什麼是泛型?知其然,知其因此然才能更好的瞭解童話是否是騙人的,所以咱們去看看官方文檔jvm

Java 類型系統中最棘手的部分之一是通配符類型(參見 Java Generics FAQ)。 而 Kotlin 中沒有。 相反,它有兩個其餘的東西:聲明處型變(declaration-site variance)與類型投影(type projections)。

看完之後,第一個感受就是咱們此處的泛型屬於聲明處型變,而且咱們的泛型約束還能夠換一種寫法,所以修改一下代碼:

open class RadiusViewDelegate<out T> @JvmOverloads constructor(
    val view: View,
    val context: Context,
    val attrs: AttributeSet? = null
) where T : RadiusViewDelegate<T> {
    fun back(): T {
        return this as T
    }
}
複製代碼

這裏的鏈式調用有童鞋建議說可使用構造者模式和接口來實現,優勢是在back方法中能夠避免這種強行轉換的方式,可是這種寫法基本上咱們的RadiusViewDelegate及其子類都須要一個單獨的接口,我認爲代碼可讀性有降低,所以沒有繼續糾結,有興趣的朋友能夠嘗試一下。

類的繼承

Kotlin當中,一個類容許被繼承只須要在class前添加一個關鍵字open,使用的時候用:替換java中的extends便可。一句話的事情,我爲何會單獨拿出來講事呢?由於在使用過程當中我遇到了兩個坑。

構造方法參數的關鍵字

我寫了一個類RadiusTextDelegate繼承自上文中的RadiusViewDelegate,在使用的時候發現一個很是奇葩的問題:其父類RadiusViewDelegate的代碼報錯,可是單獨使用其父類RadiusViewDelegate的時候一切正常。報錯代碼以下:

val mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RadiusView)
 
 //日誌
 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.TypedArray android.content.Context.obtainStyledAttributes(android.util.AttributeSet, int[])' on a null object reference
        at com.vincent.baselibrary.widget.radius.delegate.RadiusViewDelegate.<init>(RadiusViewDelegate.kt:96)
複製代碼

添加斷點檢查的時候,父類和子類的參數都同樣,貌似均不爲空。

就是這個斷點,讓我誤覺得contextattrs均不爲空,後來通過請教朱凱大佬才明白attrs已經爲空了! 咱們再來看看這個源碼:

open class RadiusViewDelegate<out T> @JvmOverloads constructor(
    val view: View,
    open val context: Context,
    open val attrs: AttributeSet? = null
) where T : RadiusViewDelegate<T> {
      init {
        val mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RadiusView)
        initAttributes(mTypedArray)

        ...
    }
    ...
}

open class RadiusTextDelegate<T> constructor(
    private val textView: TextView,
    override val context: Context,
    override val attrs: AttributeSet?
) :
    RadiusViewDelegate<T>(textView, context, attrs) where T : RadiusViewDelegate<T> {
        
    }
複製代碼

看了一下源碼更加不明白,爲何contextattrs傳給父類後就空了呢?經過面向QQ羣編程發現無效,後來嘗試將Kotlin代碼轉化爲Java代碼後發現了問題:

package com.vincent.baseproject.ui;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0006\b\u0016\u0018\u0000*\u000e\b\u0000\u0010\u0001*\b\u0012\u0004\u0012\u0002H\u00010\u00022\b\u0012\u0004\u0012\u0002H\u00010\u0002B\u001f\u0012\u0006\u0010\u0003\u001a\u00020\u0004\u0012\u0006\u0010\u0005\u001a\u00020\u0006\u0012\b\u0010\u0007\u001a\u0004\u0018\u00010\b¢\u0006\u0002\u0010\tR\u0016\u0010\u0007\u001a\u0004\u0018\u00010\bX\u0096\u0004¢\u0006\b\n\u0000\u001a\u0004\b\n\u0010\u000bR\u0014\u0010\u0005\u001a\u00020\u0006X\u0096\u0004¢\u0006\b\n\u0000\u001a\u0004\b\f\u0010\rR\u000e\u0010\u0003\u001a\u00020\u0004X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006\u000e"},
   d2 = {"Lcom/vincent/baseproject/ui/RadiusTextDelegate;", "T", "Lcom/vincent/baseproject/ui/RadiusViewDelegate;", "textView", "Landroid/widget/TextView;", "context", "Landroid/content/Context;", "attrs", "Landroid/util/AttributeSet;", "(Landroid/widget/TextView;Landroid/content/Context;Landroid/util/AttributeSet;)V", "getAttrs", "()Landroid/util/AttributeSet;", "getContext", "()Landroid/content/Context;", "app_debug"}
)
public class RadiusTextDelegate extends RadiusViewDelegate {
   private final TextView textView;
   @NotNull
   private final Context context;
   @Nullable
   private final AttributeSet attrs;

   @NotNull
   public Context getContext() {
      return this.context;
   }

   @Nullable
   public AttributeSet getAttrs() {
      return this.attrs;
   }

   public RadiusTextDelegate(@NotNull TextView textView, @NotNull Context context, @Nullable AttributeSet attrs) {
      Intrinsics.checkParameterIsNotNull(textView, "textView");
      Intrinsics.checkParameterIsNotNull(context, "context");
      super((View)textView, context, attrs);
      this.textView = textView;
      this.context = context;
      this.attrs = attrs;
   }
}
// RadiusViewDelegate.java
package com.vincent.baseproject.ui;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import com.vincent.baseproject.R.styleable;
import kotlin.Metadata;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@Metadata(
   mv = {1, 1, 15},
   bv = {1, 0, 3},
   k = 1,
   d1 = {"\u0000,\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0000\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\b\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\b\u0016\u0018\u0000*\u0010\b\u0000\u0010\u0001 \u0001*\b\u0012\u0004\u0012\u0002H\u00010\u00002\u00020\u0002B#\b\u0007\u0012\u0006\u0010\u0003\u001a\u00020\u0004\u0012\u0006\u0010\u0005\u001a\u00020\u0006\u0012\n\b\u0002\u0010\u0007\u001a\u0004\u0018\u00010\b¢\u0006\u0002\u0010\tJ\u0012\u0010\u0010\u001a\u00020\u00112\b\u0010\u0012\u001a\u0004\u0018\u00010\u0013H\u0002R\u0016\u0010\u0007\u001a\u0004\u0018\u00010\bX\u0096\u0004¢\u0006\b\n\u0000\u001a\u0004\b\n\u0010\u000bR\u0014\u0010\u0005\u001a\u00020\u0006X\u0096\u0004¢\u0006\b\n\u0000\u001a\u0004\b\f\u0010\rR\u0011\u0010\u0003\u001a\u00020\u0004¢\u0006\b\n\u0000\u001a\u0004\b\u000e\u0010\u000f¨\u0006\u0014"},
   d2 = {"Lcom/vincent/baseproject/ui/RadiusViewDelegate;", "T", "", "view", "Landroid/view/View;", "context", "Landroid/content/Context;", "attrs", "Landroid/util/AttributeSet;", "(Landroid/view/View;Landroid/content/Context;Landroid/util/AttributeSet;)V", "getAttrs", "()Landroid/util/AttributeSet;", "getContext", "()Landroid/content/Context;", "getView", "()Landroid/view/View;", "initAttributes", "", "typedArray", "Landroid/content/res/TypedArray;", "app_debug"}
)
public class RadiusViewDelegate {
   @NotNull
   private final View view;
   @NotNull
   private final Context context;
   @Nullable
   private final AttributeSet attrs;

   private final void initAttributes(TypedArray typedArray) {
   }

   @NotNull
   public final View getView() {
      return this.view;
   }

   @NotNull
   public Context getContext() {
      return this.context;
   }

   @Nullable
   public AttributeSet getAttrs() {
      return this.attrs;
   }

   @JvmOverloads
   public RadiusViewDelegate(@NotNull View view, @NotNull Context context, @Nullable AttributeSet attrs) {
      Intrinsics.checkParameterIsNotNull(view, "view");
      Intrinsics.checkParameterIsNotNull(context, "context");
      super();
      this.view = view;
      this.context = context;
      this.attrs = attrs;
      TypedArray typedArray = this.getContext().obtainStyledAttributes(this.getAttrs(), styleable.RadiusView);
      this.initAttributes(typedArray);
   }

   // $FF: synthetic method
   public RadiusViewDelegate(View var1, Context var2, AttributeSet var3, int var4, DefaultConstructorMarker var5) {
      if ((var4 & 4) != 0) {
         var3 = (AttributeSet)null;
      }

      this(var1, var2, var3);
   }

   @JvmOverloads
   public RadiusViewDelegate(@NotNull View view, @NotNull Context context) {
      this(view, context, (AttributeSet)null, 4, (DefaultConstructorMarker)null);
   }
}
複製代碼

仔細查看RadiusViewDelegate的構造方法RadiusViewDelegate(@NotNull View view, @NotNull Context context, @Nullable AttributeSet attrs)方法下第七行代碼得知,contextattrs並非使用構造方法的參數,而是經過get方法獲取的,而問題就出在get方法。由於RadiusTextDelegate的構造方法參數context使用了兩個關鍵字override val,因此將該文件轉成Java代碼後子類生成了以下方法:

@NotNull
   public Context getContext() {
      return this.context;
   }
複製代碼

話說回來,父類經過getContext()方法獲取Context時,子類尚未來得及將參數賦值給成員變量this.context,所以就產生了異常'android.content.res.TypedArray android.content.Context.obtainStyledAttributes(android.util.AttributeSet, int[])' on a null object reference。 解決方案很簡單,將子類的構造方法參數修改一下便可:

open class RadiusViewDelegate<out T> @JvmOverloads constructor(
    val view: View,
    val context: Context,
    val attrs: AttributeSet? = null
) where T : RadiusViewDelegate<T> {
    
}

open class RadiusTextDelegate<T> constructor(
    private val textView: TextView,
    context: Context,
    attrs: AttributeSet?
) :
    RadiusViewDelegate<T>(textView, context, attrs) where T : RadiusViewDelegate<T> {
        
    }
複製代碼

經過上面的例子能夠簡單的說一下構造方法參數關鍵字的用法,valvar就不解釋了,open表明子類會重寫父類的get方法和set方法(若是是var類型參數),而子類若是使用和父類徹底一致的參數名稱,則不能不添加override關鍵字。添加override關鍵字之後,若是父類的參數是var則子類也不能修改成val類型,反之,子類構造方法參數的類型則不受限制了。

構造方法的關鍵字

通常咱們在自定義View的時候,常見構造方法有以下兩種有隱患的寫法,以下:

/// 第一種
class CountdownView: TextView{
    constructor(context: Context) : this(context,null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs,0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
}
/// 第二種
class CountdownView @JvmOverloads constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : TextView(context, attrs, defStyleAttr) {
    
}
複製代碼

我在自定義RadiusSwitch的時候使用了第二種構造方法,結果遇到了一堆異常。

java.lang.NullPointerException: Attempt to invoke interface method 'int java.lang.CharSequence.length()' on a null object reference
        at android.widget.Switch.makeLayout(Switch.java:896)
        at android.widget.Switch.onMeasure(Switch.java:815)
複製代碼

網上百度、谷歌找到如下幾種解決方案:

  • theme設置錯誤——未發現錯誤
  • Context設置錯誤——斷點檢查是當前Activity
  • 添加textOfftextOn屬性——添加之後Switch的樣式顯示有問題,可是能解決閃退。

經過和原生的Switch添加斷點對比之後發現是mShowText未被設置爲true,可是經過xml文件配置屬性可解決。接下來又發現Switch的點擊事件無效了。最後查看源碼發現是clickable也被設置爲false,致使點擊事件無效。固然,也能夠經過xml配置屬性解決。 可是始終是沒有找到問題的根源,最後再次檢查源碼發現原來是構造方法使用錯誤,由於我調用的是Switch(Context context, AttributeSet attrs, int defStyleAttr),而xml佈局文件中的控件是使用的構造方法應該是Switch(Context context, AttributeSet attrs),而兩者的構造方法區別在於下面:

public Switch(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.switchStyle);
    }
public Switch(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }
複製代碼

找到錯誤的根本緣由之後,解決就很簡單了:固然再也不是xml配置上面提到的這些默認屬性了,而是修改構造方法,以下:

class RadiusSwitch : Switch {
    var delegate: RadiusSwitchDelegateImp? = null

    constructor(context: Context) : super(context) {
        delegate = RadiusSwitchDelegateImp(this, context, null)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs,0) {
        delegate = RadiusSwitchDelegateImp(this, context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) {
        delegate = RadiusSwitchDelegateImp(this, context, attrs)
    }
}
複製代碼

項目使用

到此實戰填坑就結束了,接下來仍是給你們看看這個模塊的效果圖,而後告訴你們怎麼使用。

效果圖1

效果圖2

效果圖3

<!--View默認樣式-->
    
    <!-- 圓角矩形背景色 -->
    <attr name="rv_backgroundColor" format="color"/>
    <!-- 圓角矩形背景色Pressed -->
    <attr name="rv_backgroundPressedColor" format="color"/>
    <!-- 圓角矩形背景色Disabled -->
    <attr name="rv_backgroundDisabledColor" format="color"/>
    <!-- 圓角矩形背景色Selected -->
    <attr name="rv_backgroundSelectedColor" format="color"/>
    <!-- 圓角矩形背景色Checked -->
    <attr name="rv_backgroundCheckedColor" format="color"/>
    <!-- 圓角矩形背景色按下狀態透明度(0-255默認0 僅當未設置backgroundPressedColor有效) -->
    <attr name="rv_backgroundPressedAlpha" format="integer"/>
    <!-- 圓角邊框顏色-->
    <attr name="rv_strokeColor" format="color"/>
    <!-- 圓角邊框顏色Pressed -->
    <attr name="rv_strokePressedColor" format="color"/>
    <!-- 圓角邊框顏色Disabled -->
    <attr name="rv_strokeDisabledColor" format="color"/>
    <!-- 圓角邊框顏色Selected -->
    <attr name="rv_strokeSelectedColor" format="color"/>
    <!-- 圓角邊框顏色Checked -->
    <attr name="rv_strokeCheckedColor" format="color"/>
    <!-- 圓角矩形邊框色按下狀態透明度(0-255默認0 僅當未設置strokePressedColor有效) -->
    <attr name="rv_strokePressedAlpha" format="integer"/>

    <!-- 圓角線框,單位dp-->
    <attr name="rv_strokeWidth" format="dimension"/>
    <!-- 圓角線框虛線的寬度,單位dp-->
    <attr name="rv_strokeDashWidth" format="dimension"/>
    <!-- 圓角線框虛線的間隙,單位dp-->
    <attr name="rv_strokeDashGap" format="dimension"/>

    <!-- 圓角弧度是高度一半-->
    <attr name="rv_radiusHalfHeightEnable" format="boolean"/>
    <!-- 圓角矩形寬高相等,取較寬高中大值-->
    <attr name="rv_widthHeightEqualEnable" format="boolean"/>
    <!-- 圓角弧度,單位dp-->
    <attr name="rv_radius" format="dimension"/>
    <!-- 圓角弧度,單位dp,TopLeft-->
    <attr name="rv_topLeftRadius" format="dimension"/>
    <!-- 圓角弧度,單位dp,TopRight-->
    <attr name="rv_topRightRadius" format="dimension"/>
    <!-- 圓角弧度,單位dp,BottomLeft-->
    <attr name="rv_bottomLeftRadius" format="dimension"/>
    <!-- 圓角弧度,單位dp,BottomRight-->
    <attr name="rv_bottomRightRadius" format="dimension"/>
    <!-- 水波紋顏色-->
    <attr name="rv_rippleColor" format="color"/>
    <!-- 是否有Ripple效果,api21+有效-->
    <attr name="rv_rippleEnable" format="boolean"/>
    <!--View選中狀態-->
    <attr name="rv_selected" format="boolean"/>
    <!--View背景狀態進入狀態延時(非水波紋)-->
    <attr name="rv_enterFadeDuration" format="integer"/>
    <!--View背景狀態退出狀態延時(非水波紋)-->
    <attr name="rv_exitFadeDuration" format="integer"/>

    <!-- 文字顏色-->
    <attr name="rv_textColor" format="color"/>
    <!-- 文字顏色Pressed-->
    <attr name="rv_textPressedColor" format="color"/>
    <!-- 文字顏色Disabled-->
    <attr name="rv_textDisabledColor" format="color"/>
    <!-- 文字顏色Selected-->
    <attr name="rv_textSelectedColor" format="color"/>
    <!-- 文字顏色Checked-->
    <attr name="rv_textCheckedColor" format="color"/>

    <!--設置EditText在調用setText後默認光標置於末尾-->
    <attr name="rv_selectionEndEnable" format="boolean"/>
    <!--設置EditText在調用setText後默認光標置於末尾只執行一次-->
    <attr name="rv_selectionEndOnceEnable" format="boolean"/>

    <!--如下爲TextView Drawable Left Top Right Bottom 寬高及各類狀態屬性-->
    <!--是否系統自帶drawableLeft樣式-->
    <attr name="rv_leftDrawableSystemEnable" format="boolean"/>
    <!--設置drawable爲顏色值(ColorDrawable)時的圓角弧度-->
    <attr name="rv_leftDrawableColorRadius" format="dimension"/>
    <!--設置drawable爲顏色值(ColorDrawable)時是否圓形-->
    <attr name="rv_leftDrawableColorCircleEnable" format="boolean"/>
    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <attr name="rv_leftDrawableWidth" format="dimension"/>
    <attr name="rv_leftDrawableHeight" format="dimension"/>
    <attr name="rv_leftDrawable" format="reference|color"/>
    <attr name="rv_leftPressedDrawable" format="reference|color"/>
    <attr name="rv_leftDisabledDrawable" format="reference|color"/>
    <attr name="rv_leftSelectedDrawable" format="reference|color"/>
    <attr name="rv_leftCheckedDrawable" format="reference|color"/>

    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <!--是否系統自帶drawableTop樣式-->
    <attr name="rv_topDrawableSystemEnable" format="boolean"/>
    <!--設置drawable爲顏色值(ColorDrawable)時的圓角弧度-->
    <attr name="rv_topDrawableColorRadius" format="dimension"/>
    <!--設置drawable爲顏色值(ColorDrawable)時是否圓形-->
    <attr name="rv_topDrawableColorCircleEnable" format="boolean"/>
    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <attr name="rv_topDrawableWidth" format="dimension"/>
    <attr name="rv_topDrawableHeight" format="dimension"/>
    <attr name="rv_topDrawable" format="reference|color"/>
    <attr name="rv_topPressedDrawable" format="reference|color"/>
    <attr name="rv_topDisabledDrawable" format="reference|color"/>
    <attr name="rv_topSelectedDrawable" format="reference|color"/>
    <attr name="rv_topCheckedDrawable" format="reference|color"/>

    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <!--是否系統自帶drawableRight樣式-->
    <attr name="rv_rightDrawableSystemEnable" format="boolean"/>
    <!--設置drawable爲顏色值(ColorDrawable)時的圓角弧度-->
    <attr name="rv_rightDrawableColorRadius" format="dimension"/>
    <!--設置drawable爲顏色值(ColorDrawable)時是否圓形-->
    <attr name="rv_rightDrawableColorCircleEnable" format="boolean"/>
    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <attr name="rv_rightDrawableWidth" format="dimension"/>
    <attr name="rv_rightDrawableHeight" format="dimension"/>
    <attr name="rv_rightDrawable" format="reference|color"/>
    <attr name="rv_rightPressedDrawable" format="reference|color"/>
    <attr name="rv_rightDisabledDrawable" format="reference|color"/>
    <attr name="rv_rightSelectedDrawable" format="reference|color"/>
    <attr name="rv_rightCheckedDrawable" format="reference|color"/>

    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <!--是否系統自帶drawableBottom樣式-->
    <attr name="rv_bottomDrawableSystemEnable" format="boolean"/>
    <!--設置drawable爲顏色值(ColorDrawable)時的圓角弧度-->
    <attr name="rv_bottomDrawableColorRadius" format="dimension"/>
    <!--設置drawable爲顏色值(ColorDrawable)時是否圓形-->
    <attr name="rv_bottomDrawableColorCircleEnable" format="boolean"/>
    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時必須設置不然顯示不出-->
    <attr name="rv_bottomDrawableWidth" format="dimension"/>
    <attr name="rv_bottomDrawableHeight" format="dimension"/>
    <attr name="rv_bottomDrawable" format="reference|color"/>
    <attr name="rv_bottomPressedDrawable" format="reference|color"/>
    <attr name="rv_bottomDisabledDrawable" format="reference|color"/>
    <attr name="rv_bottomSelectedDrawable" format="reference|color"/>
    <attr name="rv_bottomCheckedDrawable" format="reference|color"/>
    <!--以上爲TextView Drawable Left Top Right Bottom 寬高及各類狀態屬性-->

    <!--如下爲CompoundButton ButtonDrawable 寬高及不一樣狀態屬性-->
    <!--drawable寬高屬性當drawable爲顏色值(ColorDrawable)時方有效-->
    <!--是否系統自帶Button樣式-->
    <attr name="rv_buttonDrawableSystemEnable" format="boolean"/>
    <!--設置drawable爲顏色值(ColorDrawable)時的圓角弧度-->
    <attr name="rv_buttonDrawableColorRadius" format="dimension"/>
    <!--設置drawable爲顏色值(ColorDrawable)時是否圓形-->
    <attr name="rv_buttonDrawableColorCircleEnable" format="boolean"/>
    <attr name="rv_buttonDrawableWidth" format="dimension"/>
    <attr name="rv_buttonDrawableHeight" format="dimension"/>
    <attr name="rv_buttonDrawable" format="reference|color"/>
    <attr name="rv_buttonPressedDrawable" format="reference|color"/>
    <attr name="rv_buttonDisabledDrawable" format="reference|color"/>
    <attr name="rv_buttonSelectedDrawable" format="reference|color"/>
    <attr name="rv_buttonCheckedDrawable" format="reference|color"/>
複製代碼

以上屬性也能夠經過代碼來設置,以下:

rtv_javaBg.delegate?.run {
            this.setTextCheckedColor(Color.BLUE)
            .setBackgroundCheckedColor(Color.WHITE)
            .setRadius(resources.getDimension(R.dimen.dp_radius))
            .setStrokeWidth(resources.getDimensionPixelSize(R.dimen.dp_stroke_width))
            .setStrokeColor(ContextCompat.getColor(this@RadiusActivity,android.R.color.holo_purple))
            .setStrokeDashWidth(resources.getDimension(R.dimen.dp_dash_width))
            .setStrokeDashGap(resources.getDimension(R.dimen.dp_dash_gap))
            .initShape()
        }
複製代碼

以上爲我的理解,水平有限,還請各位斧正!

源碼

示例

參考:泛型

相關文章
相關標籤/搜索