自定義view之----自定義button
前言:
唉,學習自定義view已經很長時間了,很早就想寫自定義view這類的部落格,這樣一來不僅能夠對知識的梳理與鞏固還能幫助他人。計劃再好不如即時行動更為有效,所以趁著週末趕緊把這個月的計劃完成先。
ok,廢話少說(貌似好像前面的都是廢話~ 額’),切入正題。
正題:
一般應用中按鈕(Button)都會結合自己應用的主題風格來自定義,如:qq,微博,支付寶的登陸按鈕,這裡就不貼圖了,它們登陸按鈕的共同特點都是圓角,不同的是背景顏色不同而已。如果要實現類似的效果,我想說的是 so easy!那麼,如果你看到了這裡,不管你會還是不會,這bi我還是要裝一下的。haha~
實現方式有兩種:
方法一:
只需要自定義背景屬性就能實現
首先看下效果圖,有邊框的,由於是靜態圖所以無法看到點選的效果
好了,開始貼程式碼了
xml檔案佈局程式碼:
style=”?android:attr/borderlessButtonStyle”//這一行程式碼是5.0以上版本去掉Button自帶陰影效果的方法
<Button
style="?android:attr/borderlessButtonStyle"
android:layout_marginTop="50dp"
android:layout_width ="200dp"
android:layout_height="wrap_content"
android:background="@drawable/button_click_enabled"
android:layout_gravity="center"
android:text="只設置上面兩個角為圓角"/>
<Button
android:layout_margin="20dp"
android:layout_width ="200dp"
style="?android:attr/borderlessButtonStyle"
android:layout_height="wrap_content"
android:background="@drawable/button_click_enabled_5"
android:layout_gravity="center"
android:textColor="#fff"
android:textSize="15dp"
android:text="圓角"/>
button_click_enabled.xml 檔案:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_click_unchecked" android:state_pressed="false"></item>
<item android:drawable="@drawable/button_click_checked" android:state_pressed="true"></item>
</selector>
selector選擇器的意思,顧名思義就算你沒學過你也已經知道它是幹什麼的了吧。預設顯示背景@drawable/button_click_unchecked,當只有按住按鈕(android:state_pressed=”true”時)才會顯示 背景@drawable/button_click_checked
button_click_unchecked.xml檔案:
(複製程式碼後刪掉註釋)
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/colorAccent"//控制元件顏色
/>
<corners
android:bottomLeftRadius="0dp"//左下角設定圓角半徑為0
android:bottomRightRadius="0dp"//右下角設定圓角半徑為0
android:topLeftRadius="20dp"//左上角設定圓角半徑為20
android:topRightRadius="20dp" //右上角設定圓角半徑為20
/>
<stroke
android:width="2px"//邊框寬
android:color="#2443D0"//邊框顏色
/>
</shape>
button_click_checked.xml檔案:
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fe3"></solid>
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
<stroke
android:width="2px"
android:color="#2443D0" />
</shape>
ok,
就這麼簡單。
偷偷告訴你不只是button,其他控制元件也可以這麼幹,自己去發掘吧!
方法二:
下面我要講的才算是自定義view,這種實現方式就比較高大上了,首先你需要對自定義view的知識有一定的瞭解,不瞭解也沒關係,有看不懂的地方請自行百度。如果方法一能實現需求,但你覺得太low了,那麼不要走開(裝逼模式已開啟~)。
同樣,放張效果圖:
實現思路:
系統Button是繼承Textview的,所以自定義的view也繼承Textview。
按照步驟:
1.建立類cButton繼承Textview
2.設定自定義屬性(在res/values/styles.xml中):
<declare-styleable name="cButton">
<attr name="internalcolor" format="color" />//內部填充顏色
<attr name="clickedColor" format="color" />//點選後顏色
<attr name="bordercolor" format="color" />//邊框顏色
<attr name="textcolor" format="color" />//文字顏色
<attr name="textsize" format="dimension" />//文字大小
<attr name="textstr" format="string" />//文字
<attr name="enablerd" format="boolean" />//是否可點選
<attr name="angletype" format="integer">//圓角型別
<enum name="anglecirarc" value="1" />//圓弧形
<enum name="anglecir" value="2" />//小圓角
</attr>
</declare-styleable>
3.在cButton類中對自定義屬性進行解析,解析時設定預設值
public cButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.cButton);
enabler = ta.getBoolean(R.styleable.cButton_enablerd, true);//是否可點選
AngleType = ta.getInt(R.styleable.cButton_angletype, 1);//圓角型別
clicked_color = ta.getColor(R.styleable.cButton_clickedColor, Color.parseColor("#6F4A4C58"));//點選後的顏色
border_color = ta.getColor(R.styleable.cButton_bordercolor, Color.parseColor("#40000000"));//邊框顏色
interna_Color = ta.getColor(R.styleable.cButton_internalcolor, Color.parseColor("#FF4A4C58"));//背景顏色
text_Color = ta.getColor(R.styleable.cButton_textcolor, Color.BLACK);//文字顏色
text_Size = ta.getDimension(R.styleable.cButton_textsize, 40);//文字大小
text = ta.getString(R.styleable.cButton_textstr);//文字
}
4.邏輯處理繪製圖形:
重點說一下,文字居中繪製:看這裡http://blog.csdn.net/u014702653/article/details/51985821
寬=控制元件寬度/2 - 文字寬度/2;
高=控制元件高度/2 + 文字高度/2;
tPaint.measureText(text);//文字寬度
Paint.FontMetricsInt fm = tPaint.getFontMetricsInt();
fm.bottom - fm.top//文字高度
canvas.drawText(“字串文字”, 寬, 高, tPaint);// 繪製文字
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//此處省略n條程式碼
canvas.drawText(text, startX, startY, tPaint);//繪製文字
canvas.drawRoundRect(rectF, rx, ry, Paint);//繪製圓角矩形
}
5.(能夠繪製正常影象之後)定義點選回撥介面,和觸發點選的方法
public boolean onTouchEvent(MotionEvent event) {
//cListener.click(cButton.this);//觸發點選事件
//此處省略n條程式碼
return true;
}
/**
* 定義介面
*/
public interface OncButtonListener {
void click(View v);
}
/**
* 監聽回撥方法
*/
public void setcButtonListener(OncButtonListener listener) {
cListener = listener;
}
6.定義設定屬性方法:
每個方法中都必須有invalidate()方法,不然設定無效
/**
* 設定是否可點選
*/
public void setEnabler(boolean enabler) {
this.enabler = enabler;
if (enabler) {
set_Color = interna_Color;
} else {//
set_Color = clicked_color;
}
invalidate();//重新繪製
}
/**
* 設定文字
*/
public void setText(String text) {
this.text = text;
invalidate();//重繪
}
//省略
完成。
下面貼具體程式碼:
cButton類:
/**
* Created by xxf on 2017/8/19.
*/
public class cButton extends TextView {
/* 畫筆 */
private Paint mPaint;// 填充
private Paint bPaint;// 邊框
private Paint tPaint;//繪製文字
private int mWith, mHeight;//寬、高
private Rect oRect;//
private String text;//文字
private int clicked_color;//點選後的顏色
private int interna_Color;//填充顏色
private int set_Color;//設定顏色
private int text_Color;//文字顏色
private float text_Size;//字型大小
private OncButtonListener cListener;//點選監聽
private Context mContext;
private int border_color;
private boolean enabler;//設定是否可點選
private int AngleType;//圓角樣式
public cButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.cButton);
enabler = ta.getBoolean(R.styleable.cButton_enablerd, true);//是否可點選
AngleType = ta.getInt(R.styleable.cButton_angletype, 1);//圓角型別
clicked_color = ta.getColor(R.styleable.cButton_clickedColor, Color.parseColor("#6F4A4C58"));//點選後的顏色
border_color = ta.getColor(R.styleable.cButton_bordercolor, Color.parseColor("#40000000"));//邊框顏色
interna_Color = ta.getColor(R.styleable.cButton_internalcolor, Color.parseColor("#FF4A4C58"));//背景顏色
if (enabler) {
set_Color = interna_Color;
} else {//
set_Color = clicked_color;
}
text_Color = ta.getColor(R.styleable.cButton_textcolor, Color.BLACK);//文字顏色
text_Size = ta.getDimension(R.styleable.cButton_textsize, 40);//文字大小
text = ta.getString(R.styleable.cButton_textstr);//文字
}
/*用於測量檢視的大小的*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWith = MeasureSpec.getSize(widthMeasureSpec); //取出寬度的確切數值
mHeight = MeasureSpec.getSize(heightMeasureSpec); //取出高度的確切數值
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
init();
// Log.e(TAG, "onTouchEvent: " + interna_Color);
// RectF rectF = new RectF(0 + 10, 0 + 10, mWith - 10, mHeight - 10);
if (AngleType == 1) {
// Log.e(TAG, "onDraw: " + 1);
RectF rectF = new RectF(0 + 10, 0 + 10, mWith - 10, mHeight - 10);
canvas.drawRoundRect(rectF, mHeight / 2, mHeight / 2 + 30, mPaint);
canvas.drawRoundRect(rectF,mHeight / 2, mHeight / 2 + 30, bPaint);//邊框
} else if (AngleType == 2) {
// Log.e(TAG, "onDraw: " + 2);
RectF rectF = new RectF(0 + 20, 10, mWith - 20, mHeight - 10);
canvas.drawRoundRect(rectF, mHeight / 9, mHeight / 9, mPaint);
canvas.drawRoundRect(rectF, mHeight / 9, mHeight / 9, bPaint);
// canvas.drawRoundRect(rectF, mHeight / 4, mHeight / 4, bPaint);//邊框
}
// canvas.drawText("123",mWith/2,mHeight/2,tPaint);
/*
* 控制元件寬度/2 - 文字寬度/2
*/
float v= tPaint.measureText(text);//文字寬度
float startX = getWidth() / 2 - v / 2;
/*
* 控制元件高度/2 + 文字高度/2,繪製文字從文字左下角開始,因此"+"
*/
// float startY = getHeight() / 2 + oRect.height() / 2;
Paint.FontMetricsInt fm = tPaint.getFontMetricsInt();
//fm.bottom - fm.top//文字高度
int startY = getHeight() / 2 - fm.descent + (fm.bottom - fm.top) / 2;
// 繪製文字
canvas.drawText(text, startX, startY, tPaint);
}
private void init() {
mPaint = new Paint();
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(set_Color);
mPaint.setStrokeWidth(3);
bPaint = new Paint();
bPaint.setStyle(Paint.Style.STROKE);
bPaint.setAntiAlias(true);
bPaint.setColor(border_color);
bPaint.setStrokeWidth(2);
oRect = new Rect();
tPaint = new Paint();
tPaint.setAntiAlias(true);
tPaint.setStyle(Paint.Style.FILL);
tPaint.setTextSize(text_Size);
tPaint.setColor(text_Color);
tPaint.setAntiAlias(true);
tPaint.getTextBounds(text, 0, text.length(), oRect);
tPaint.setStrokeWidth(2);
}
/**
* 呼叫 getParent().requestDisallowInterceptTouchEvent(true);
* 方法。一旦底層View收到touch的action後呼叫這個方法
* 那麼父層View就不會再呼叫onInterceptTouchEvent了
*
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
if (enabler) {
getParent().requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
public boolean onTouchEvent(MotionEvent event) {
if (enabler) {
// 手指按下:
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
set_Color = clicked_color;//設定按下顏色
invalidate();//重新繪製
break;
//手指擡起:
case MotionEvent.ACTION_UP:
if (cListener != null) {
if (event.getY() >= mHeight || event.getY() < 0 || event.getX() >= mWith || event.getX() < 0) {
} else {
cListener.click(cButton.this);
}
}
Log.e(TAG, "onTouchEvent: ------------" + event.getY());
if (enabler) {
set_Color = interna_Color;//設定擡起顏色復原
} else {
set_Color = clicked_color;
}
invalidate();
break;
// 手指正在移動:
case MotionEvent.ACTION_MOVE:
Log.e(TAG, "onTouchEvent: event.getX()===" + event.getX() + " mWith========" + mWith);
if (event.getY() >= mHeight || event.getY() < 0 || event.getX() >= mWith || event.getX() < 0) {
set_Color = interna_Color;
} else {
set_Color = clicked_color;//設定按下顏色
}
invalidate();//重新繪製
break;
}
}
return true;
}
/**
* 定義介面
*/
public interface OncButtonListener {
void click(View v);
}
/**
* 監聽回撥方法
*/
public void setcButtonListener(OncButtonListener listener) {
cListener = listener;
}
/**
* 設定是否可點選
*/
public void setEnabler(boolean enabler) {
this.enabler = enabler;
if (enabler) {
set_Color = interna_Color;
} else {//
set_Color = clicked_color;
}
setInvalidate();
}
/**
* 設定文字
*/
public void setText(String text) {
this.text = text;
setInvalidate();
}
/**
* 重繪
*/
public void setInvalidate() {
invalidate();
}
}
layout佈局中使用:
宣告名稱空間:xmlns:cButton=”http://schemas.android.com/apk/res-auto”
<xxf.com.buttontest.cButton
android:id="@+id/cButton"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginTop="50dp"
cButton:enablerd="true"
cButton:internalcolor="@color/colorPrimary"
cButton:textcolor="#fff"
cButton:textsize="20dp"
cButton:textstr="圓弧邊" />
<xxf.com.buttontest.cButton
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="center"
cButton:angletype="anglecir"
cButton:internalcolor="@color/colorPrimary"
cButton:textcolor="#fff"
cButton:textsize="15dp"
cButton:textstr="圓角" />
結束。
謝謝觀看!