CardView改變陰影顏色

宜鵬發表於2018-09-22

CardView改變陰影顏色

專案GitHub地址 : CardViewShadowColor

  • CardView本身自帶了灰色的陰影顏色,但是是不可修改的,而UI往往要求按鈕的顏色是紅色的就需要紅色的陰影,在GitHub上搜尋ShadowLayout等關鍵字,找到一些實現陰影的庫,但有的效果不好,有效能有問題,會一直重繪,導致cpu及記憶體佔用過高,介面卡頓,甚至OOM。

  • 之前一直百思不得其解,為什麼不讓CardView能自定義陰影顏色呢,看了原始碼才搞清楚意圖,我猜測有兩個原因:

  1. 因為不想讓使用者隨便改變陰影顏色,因為自然界中不管什麼顏色的物體,其陰影都是灰色

  2. API >=21 View支援了陰影,只能在5.0以上的手機上生效,而API < 21 陰影都是重新繪製的,而View預設的陰影是灰色的,所以API < 21 重新繪製的陰影其顏色也給寫死了灰色,且不提供public api供外接訪問,應該是為了5.0以上手機使用陰影有更高的效率

CardView values.xml檔案
<color name="cardview_shadow_end_color">#03000000</color>
<color name="cardview_shadow_start_color">#37000000</color>

RoundRectDrawableWithShadow(Resources resources, ColorStateList backgroundColor, float radius,
            float shadowSize, float maxShadowSize) {
    mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color);
    mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color);
       
}

複製程式碼
  • 可以看出其實是支援自定義陰影顏色的,只不過在程式碼裡給寫死了,且未提供公開的api修改顏色的方法或屬性
static {
    if (Build.VERSION.SDK_INT >= 21) {
        IMPL = new CardViewApi21Impl();
    } else if (Build.VERSION.SDK_INT >= 17) {
        IMPL = new CardViewApi17Impl();
    } else {
        IMPL = new CardViewBaseImpl();
    }
    IMPL.initStatic();
}

複製程式碼
  • 直接改變values.xml中的cardview_shadow_end_color與cardview_shadow_start_color在5.0及以上的手機中是不生效的,因為5.0以上的手機,根本不建立RoundRectDrawableWithShadow類,而是使用View自帶的陰影方法設定的,所以不管怎麼改變一直是灰色陰影,所以要想在5.0及以上的手機上可以改變陰影顏色,可以修改下程式碼,如下所示:
static {
    //if (Build.VERSION.SDK_INT >= 21) {
    //    IMPL = new CardViewApi21Impl();
    //} else 
    if (Build.VERSION.SDK_INT >= 17) {
        IMPL = new CardViewApi17Impl();
    } else {
        IMPL = new CardViewBaseImpl();
    }
    IMPL.initStatic();
}
複製程式碼
  • 這樣就可以強制使其執行RoundRectDrawableWithShadow類來繪製陰影,改的顏色值也就生效了

  • 如果沒有必須改變陰影顏色的需求,還是直接使用預設的,這樣效能更好

  • 為了更方便的使用支援改變陰影顏色的CardView,我基於CardView 24.2.1版本改寫了支援改變陰影顏色的庫, 為了和官方的CardView庫共存,且不衝突,我把所有屬性、color及style的命名都加了字首yc,當然也可以單獨使用,使用方式如下

builb.gradle

最好和官方的CardView庫一起使用,不需要特殊修改陰影顏色的地方,使用官方的CardView,
需要修改View陰影的地方才使用YcCardView
implementation 'com.zyp.cardview:cardview:1.0.1'
複製程式碼

pom.xml

<dependency>
  <groupId>com.zyp.cardview</groupId>
  <artifactId>cardview</artifactId>
  <version>1.0.1</version>
  <type>pom</type>
</dependency>

複製程式碼
    <!--android:foreground="@drawable/item_selector"  api>=21 ripper  api<21 selector-->
    <!--android:stateListAnimator="@drawable/state_list_animator" 點選動畫效果 支援api>=21-->
    <!--CardView 預設使用-->
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:clickable="true"
        android:focusable="true"
        android:foreground="@drawable/item_selector"
        android:stateListAnimator="@drawable/state_list_animator"
        app:cardBackgroundColor="@color/white"
        app:cardCornerRadius="5dp"
        app:cardElevation="5dp"
        app:cardMaxElevation="5dp"
        app:cardPreventCornerOverlap="false">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@null"
            android:gravity="center"
            android:text="Hello World!" />
    </android.support.v7.widget.CardView>
    <!--YcCardView的使用-->
    <!--ripper的範圍無法控制-->
    <com.zyp.cardview.YcCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:clickable="true"
        android:focusable="true"
        android:foreground="@drawable/item_selector"
        android:stateListAnimator="@drawable/state_list_animator"
        app:ycCardCornerRadius="5dp"
        app:ycCardElevation="5dp"
        app:ycCardMaxElevation="5dp"
        app:ycCardPreventCornerOverlap="true"
        app:ycStartShadowColor="@color/red">
        <!--只用設定開始顏色ycStartShadowColor,ycStartShadowColor預設值為#00ffffff 一般不用設定-->

        <TextView
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center"
            android:text="Hello World!" />
    </com.zyp.cardview.YcCardView>

複製程式碼
  • 在引用第三方的UI庫,特別是View繪製相關的,如果View本身沒有變化,draw()方法卻一直執行,這種問題就非常嚴重了,但是這種問題卻是最好排查的,Android Studio自帶的工具Android Device Monitor就可以輕鬆實現排查,如下圖:

CardView改變陰影顏色
CardView改變陰影顏色

當然也可以使用Android Profiler,但是貌似不可以按照包名搜尋。

CardView改變陰影顏色
CardView改變陰影顏色

相關文章