標籤:要求 ESS prot 自訂控制項 this bsp sed bottom tag
使用xml實現邊框
原來使用帶邊框的TextView時一般都是用XML定義來完成,在drawable目錄中定義如下所示的xml檔案:
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 點擊狀態下按鈕背景樣式 --> <item android:state_pressed="true"> <shape android:shape="rectangle"> <corners android:radius="2dp"/> <solid android:color="@android:color/transparent"/> <stroke android:width="1dp" android:color="#ff48beab"/> </shape> </item> <!-- 正常點擊狀態下按鈕背景樣式 --> <item android:state_pressed="false"> <shape android:shape="rectangle"> <corners android:radius="2dp"/> <solid android:color="@android:color/transparent"/> <stroke android:width="1dp" android:color="#ff48baab"/> </shape> </item></selector>
這樣可以實現圓角邊框,但顏色是固定的,如果需要在不同位置放置不同的TextView(比如多種顏色的按鈕),那麼就要定義多個顏色不同的XML檔案。
自訂帶邊框的TextView
最近在做項目時遇到多種顏色的標籤需求,如果還是按照上面的做法,那麼需要多套XML檔案配合,於是我想了一下,能不能自訂一個控制項,讓邊框顏色在使用時指定。
在項目的設計圖中主要是用於一些標籤,如所示:
接下來我就嘗試了一下,發現是可行的,於是就有了下面這個自訂,在個人項目中基本夠用。
這個控制項是繼承自TextView的,只是在onDraw方法中畫了一個邊框,並設計了幾個自訂屬性用來更靈活地控制控制項。
自訂屬性如下:
<declare-styleable name="BorderTextView"> <attr name="strokeWidth" format="dimension"/> <attr name="cornerRadius" format="dimension"/> <attr name="strokeColor" format="color"/> <attr name="followTextColor" format="boolean"/></declare-styleable>
這幾個屬性簡要解釋如下:
- strokeWidth
邊框的寬度,預設為1dp
- cornerRadius
圓角半徑,預設為2dp
- strokeColor
邊框顏色,預設是沒有邊框即顏色為Color.TRANSPARENT
- followTextColor
邊框是否跟隨文字顏色,預設是true
自訂控制項代碼(BorderTextView ):
package com.witmoon.eab.widget;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.RectF;import android.support.annotation.NonNull;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.TypedValue;import android.widget.TextView;import com.witmoon.eab.R;/** * 用於作為標籤顯示的TextView * 邊框預設與文字顏色一致 * Created by chuxin on 2015/9/11. */public class BorderTextView extends TextView { public static final float DEFAULT_STROKE_WIDTH = 1.0f; // 預設邊框寬度, 1dp public static final float DEFAULT_CORNER_RADIUS = 2.0f; // 預設圓角半徑, 2dp public static final float DEFAULT_LR_PADDING = 6f; // 預設左右內邊距 public static final float DEFAULT_TB_PADDING = 2f; // 預設上下內邊距 private int strokeWidth; // 邊框線寬 private int strokeColor; // 邊框顏色 private int cornerRadius; // 圓角半徑 private boolean mFollowTextColor; // 邊框顏色是否跟隨文字顏色 private Paint mPaint = new Paint(); // 畫邊框所使用畫筆對象 private RectF mRectF; // 畫邊框要使用的矩形 public BorderTextView(Context context) { this(context, null); } public BorderTextView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public BorderTextView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // 將DIP單位預設值轉為PX DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); strokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_STROKE_WIDTH, displayMetrics); cornerRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_RADIUS, displayMetrics); // 讀取屬性值 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BorderTextView); strokeWidth = ta.getDimensionPixelSize(R.styleable.BorderTextView_strokeWidth, strokeWidth); cornerRadius = ta.getDimensionPixelSize(R.styleable.BorderTextView_cornerRadius, cornerRadius); strokeColor = ta.getColor(R.styleable.BorderTextView_strokeColor, Color.TRANSPARENT); mFollowTextColor = ta.getBoolean(R.styleable.BorderTextView_followTextColor, true); ta.recycle(); mRectF = new RectF(); // 邊框預設顏色與文字顏色一致// if (strokeColor == Color.TRANSPARENT)// strokeColor = getCurrentTextColor(); // 如果使用時沒有設定內邊距, 設定預設邊距 int paddingLeft = getPaddingLeft() == 0 ? (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LR_PADDING, displayMetrics) : getPaddingLeft(); int paddingRight = getPaddingRight() == 0 ? (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LR_PADDING, displayMetrics) : getPaddingRight(); int paddingTop = getPaddingTop() == 0 ? (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_TB_PADDING, displayMetrics) : getPaddingTop(); int paddingBottom = getPaddingBottom() == 0 ? (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, DEFAULT_TB_PADDING, displayMetrics) : getPaddingBottom(); setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom); } @Override protected void onDraw(@NonNull Canvas canvas) { super.onDraw(canvas); mPaint.setStyle(Paint.Style.STROKE); // 空心效果 mPaint.setAntiAlias(true); // 設定畫筆為無鋸齒 mPaint.setStrokeWidth(strokeWidth); // 線寬 // 設定邊框線的顏色, 如果聲明為邊框跟隨文字顏色且當前邊框顏色與文字顏色不同時重新設定邊框顏色 if (mFollowTextColor && strokeColor != getCurrentTextColor()) strokeColor = getCurrentTextColor(); mPaint.setColor(strokeColor); // 畫空心圓角矩形 mRectF.left = mRectF.top = 0.5f * strokeWidth; mRectF.right = getMeasuredWidth() - strokeWidth; mRectF.bottom = getMeasuredHeight() - strokeWidth; canvas.drawRoundRect(mRectF, cornerRadius, cornerRadius, mPaint); }}
代碼中的注釋也比較詳細了,而且也非常簡單,因此這裡應該不需要贅述。唯一需要注意的是在畫邊框時使用的RectF尺寸,如果邊框寬度較寬,由於Paint筆觸是在邊框中線為準,因此如果左上方指定為(0,0)話,會有一半邊框寬度的線是畫在不見地區的;這裡指定左上方座標為 0.5f * strokeWidth(即半個邊框寬度)即可,右下角也需要作同樣的考慮。
使用
自訂控制項的使用就更簡單了,這裡我沒有設定自訂屬性,一切採用預設值:
<com.witmoon.eab.widget.BorderTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="身分識別驗證" android:textColor="@color/tag_text_blue"/>
展示效果如所示:
基本上滿足要求。
作為按鈕使用
在某些時候,我們可能會需要一些這種中間鏤空的按鈕,BorderTextView也可以用在這種情況下,下面是個例子。
首先在values目錄中建立一個colors目錄,在其中建立一個xml檔案(button_text_color.xml),內容如下
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/secondary_text" android:state_pressed="true"/> <item android:color="@color/hint_text" android:state_enabled="false"/> <item android:color="@color/primary_text"/></selector>
其實是為按鈕在不同狀態下指定不同的顏色,以響應點擊或禁用操作,增加使用者體驗。
<com.witmoon.eab.widget.BorderTextView android:id="@+id/retrieve_check_code_again" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="6dp" android:enabled="false" android:textColor="@color/button_text_color" android:paddingTop="6dp" android:text="重新發送"/>
由於預設情況下邊框是跟隨文字顏色的,因此在被點擊或者禁用時TextView會重新繪製,邊框也隨之改變顏色。
Android自訂控制項 -- 帶邊框的TextView