天天看點

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

前言

作為一個android程式員,對于shape、selector這兩個标簽一定不陌生。每當UI設計師給我們設計出一個個button背景的時候,我們就需要去drawable檔案夾下去建立一個bg_xxx.xml,然後很多時候差別僅僅是一個邊框的顔色或者填充的顔色。這就導緻了很多非常相似的.xml檔案産生。

網上之前也有了一種通過自定義View,在xml中通過設定屬性達到shape效果的控件。但是這種自定義的控件不太靈活,歸根到底是一個自定義的button,如果我想改造項目的話就得去替換原有的button或者textView。接下來就給大家提供一種更加簡單的方式:

無需自定義View,直接添加屬性便可以實作shape、selector效果。

具體内容

效果展示

話不多說,直接上代碼。

使用方法:

1、在BaseActiviy的super.onCreate()之前調用一行代碼,僅僅是一個方法

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

2、沒有其他操作了,直接layout裡開始寫控件吧!

布局代碼

我們來添加一些執行個體屬性:

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

有沒有覺得很熟悉,就是原生标簽的tag名+_+屬性名,很容易記住,而且不管是Button還是TextView,隻要是View都可以。

效果

我們來看一下實際效果:

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

修改背景

現在UI設計師告訴我們要改一下背景,沒事,我們隻需要在xml添加或者修改屬性就行。

我們來把圓形改成正方形,加個邊框。5秒ok!

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

簡單的原了解析

app:xxx

app:xxx屬性就不用多說了,這些就是一些自定義屬性而已。在這裡我把shape、selector的部分屬性轉換成自定義的屬性,這樣就友善添加到已有原生控件中。

BackgroundLibrary.inject(this)

這個方法是這個架構唯一需要加入的代碼。

inject中實際上是給LayoutInflater添加了一個LayoutInflater.Factory類。而Android的Activity在建立過程(也就是setContentView)中實際上是通過把xml轉換成View的對象。而LayoutInflater.Factory相當于這中間的一個後門,它是xml解析建立成View的必經方法,google中的v7support包裡很多内容就是通過LayoutInflater.Factory來實作向下相容的。

在這裡,我通過低入侵的方式,加入一個自定義的LayoutInflater.Factory,去解析添加的自定義屬性,接下來就簡單了。生成系統提供的GradientDrawable、RippleDrawable、StateListDrawable即可。

同時由于AppcompatActivity是已經實作了LayoutInflater.Factory,而Activity又設定一個Activity隻能加入一個factory類,是以這裡需要在super.onCreate之前調用該方法,利用AppcompatActivity的factory去建立View。

具體原了解釋可以參考我的這篇文章:Android 常用換膚方式以及原理分析

具體使用方法:

添加依賴:

implementation 'com.noober.background:core:1.2.0'
           

BaseActivity的super.onCreate之前添加代碼:

BackgroundLibrary.inject(context);
           

支援屬性,命名規則就是标簽名_标簽屬性名,支援shape所有屬性:

<attr name="shape" format="enum">
       <enum name="rectangle" value="0" />
       <enum name="oval" value="1" />
       <enum name="line" value="2" />
       <enum name="ring" value="3" />
   </attr>

   <attr name="solid_color" format="color"/>

   <attr name="corners_radius" format="dimension"/>
   <attr name="corners_bottomLeftRadius" format="dimension"/>
   <attr name="corners_bottomRightRadius" format="dimension"/>
   <attr name="corners_topLeftRadius" format="dimension"/>
   <attr name="corners_topRightRadius" format="dimension"/>

   <attr name="gradient_angle" format="integer"/>
   <attr name="gradient_centerX" format="float"/>
   <attr name="gradient_centerY" format="float"/>
   <attr name="gradient_centerColor" format="color"/>
   <attr name="gradient_endColor" format="color"/>
   <attr name="gradient_startColor" format="color"/>
   <attr name="gradient_gradientRadius" format="dimension"/>
   <attr name="gradient_type" format="enum">
       <enum name="linear" value="0" />
       <enum name="radial" value="1" />
       <enum name="sweep" value="2" />
   </attr>
   <attr name="gradient_useLevel" format="boolean"/>

   <attr name="padding_left" format="dimension"/>
   <attr name="padding_top" format="dimension"/>
   <attr name="padding_right" format="dimension"/>
   <attr name="padding_bottom" format="dimension"/>

   <attr name="size_width" format="dimension">
       <enum name="wrap_content" value="-2" />
       <enum name="match_parent" value="-1" />
   </attr>
   <attr name="size_height" format="dimension">
       <enum name="wrap_content" value="-2" />
       <enum name="match_parent" value="-1" />
   </attr>

   <attr name="stroke_width" format="dimension"/>
   <attr name="stroke_color" format="color"/>
   <attr name="stroke_dashWidth" format="dimension"/>
   <attr name="stroke_dashGap" format="dimension"/>

   <!--以下是selector事件-->
   <attr name="ripple_enable" format="boolean"/>
   <attr name="ripple_color" format="color"/>
   <attr name="unpressed_color" format="color"/>
   <attr name="pressed_color" format="color"/>
           

例如加一個邊框背景,如下即可:

<TextView
    android:layout_width="130dp"
    android:layout_height="36dp"
    android:gravity="center"
    android:text="TextView"
    android:textColor="#8c6822"
    android:textSize="20sp"
    app:corners_radius="4dp"
    app:solid_color="#E3B666"
    app:stroke_color="#8c6822"
    app:stroke_width="2dp" />
           

如果需要selector效果,需要同時添加

app:unpressed_color
app:pressed_color
           

如果需要水波紋效果,5.0以上才支援:

app:ripple_enable="true"//打開水波紋開關
app:solid_color="xxx"//設定預設填充顔色
app:ripple_color="xxx"//設定水波紋顔色
           

注意:

1、如果直接給原生控件添加屬性,在xml中會如下報紅色異常,這時候不用理會即可。

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

但是紅色多了,顯示總歸難受,可以在根節點添加

tools:ignore="MissingPrefix" 
           

即可

無需自定義View,徹底放棄shape,selector吧前言具體内容結尾

2、如果Button設定背景的時候文字顯示不全,需要設定padding為0,這是button的系統預設風格導緻的。

結尾

項目位址:https://github.com/JavaNoober/BackgroudLibrary

後續更新完善内容會在項目裡标明,大家的star是我繼續研究的動力☺!

【最新版本已支援selector,詳情檢視 https://github.com/JavaNoober/BackgroundLibrary

繼續閱讀