由於項目須要只有邊框和文字漸變效果得按鈕,嘗試過用drawable文件設置,發現只能設置全背景漸變效果,也懶得用其餘方式,就本身動手畫了一個,畫完以後就把全背竟的也給加上了,由於這個項目相似這種的按鈕還很多,避免了挨個去建立drawable文件了。當我寫完以後,微信就更新了8.0發現這個按鈕跟微信8.0的狀態按鈕挺像,就起了這麼一個標題java
自定義View相關的代碼
最開始畫這個控件的時候,繼承的是View,本身用畫筆去繪製文字,發現居中一直有問題,算了一下午的文字居中發現沒有任何屌用,後來小夥伴跟我說,那你就繼承TextView,而後直接設置文字居中不就行了,當時感受本身的智商被人摁在地上摩擦。。。。。android
package com.ltb.myroundtextlibrary.widget; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import androidx.annotation.Nullable; import com.ltb.myroundtextlibrary.R; import com.ltb.myroundtextlibrary.utils.SizeUtils; public class MyRoundTextView extends androidx.appcompat.widget.AppCompatTextView { //邊框畫筆 private Paint mPaint; private Context mContext; private int mHeight; private int mWidth; //文字寬度 private int txtWidth; //文字長度 private int txtLength; private int strokeWidth = SizeUtils.dp2px(1); //起始顏色 private int startColor; //結束顏色 private int endColor; //文字 private String txt = ""; private String content1; private String content2; //判斷是不是全漸變背景 private boolean isFull = false; public MyRoundTextView(Context context) { super(context); } public MyRoundTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(attrs); } public MyRoundTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(attrs); } private void init(AttributeSet attrs) { mContext = getContext(); startColor = mContext.getResources().getColor(R.color.colorForgetPwd); endColor = mContext.getResources().getColor(R.color.colorForgetPwd); //獲取自定義參數 TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.MyRoundTextView, 0, 0); //獲取起始顏色 startColor = typedArray.getColor(R.styleable.MyRoundTextView_m_gradient_color_start, startColor); //獲取結束顏色 endColor = typedArray.getColor(R.styleable.MyRoundTextView_m_gradient_color_end, endColor); //獲取邊框粗細 strokeWidth = (int) typedArray.getDimension(R.styleable.MyRoundTextView_m_stroke_width, strokeWidth); //是否填滿 isFull = typedArray.getBoolean(R.styleable.MyRoundTextView_m_is_full, isFull); txt = getText().toString(); typedArray.recycle(); //配置邊框畫筆 mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(strokeWidth); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); mWidth = measureWidth(widthMeasureSpec); mHeight = measureHeight(heightMeasureSpec); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { //判斷是否漸變鋪滿 mPaint.setStyle(!isFull ? Paint.Style.STROKE : Paint.Style.FILL); //設置漸變參數 LinearGradient linearGradient = new LinearGradient( strokeWidth, strokeWidth, mWidth, mHeight, endColor, startColor, Shader.TileMode.CLAMP); mPaint.setShader(linearGradient); RectF r2 = new RectF(); r2.set(strokeWidth * 2, strokeWidth * 2, mWidth - strokeWidth * 4, mHeight - strokeWidth * 4); //繪製圓角 canvas.drawRoundRect(r2, SizeUtils.dp2px(20), SizeUtils.dp2px(20), mPaint); super.onDraw(canvas); if (txtLength == 0) { if (!txtIsEmpty(txt)) { setTextViewStyles(); } } } private boolean txtIsEmpty(String txt) { return TextUtils.isEmpty(txt); } /** * 設置文字漸變 */ private void setTextViewStyles() { txtWidth = (int) getPaint().measureText(txt); txtLength = txt.length(); if (getGravity() != Gravity.CENTER) { setGravity(Gravity.CENTER); } //當全漸變背景時候 默認設置文字顏色爲白色 不設置成爲漸變 if (!isFull) { int x0 = mWidth / 2 - txtWidth / 2; int y0 = getBottom(); int x1 = mWidth / 2 + txtWidth / 2; LinearGradient txtLinearGradient = new LinearGradient( x0, y0, x1, y0, endColor, startColor, Shader.TileMode.CLAMP ); getPaint().setShader(txtLinearGradient); } else { getPaint().setShader(null); setTextColor(Color.WHITE); getPaint().setColor(Color.WHITE); } if (!TextUtils.isEmpty(content1) || !TextUtils.isEmpty(content2)) { txt = isFull ? content1 : content2; } setText(txt); invalidate(); } /** * 設置狀態改變先後的文字信息 * * @param content1 點擊前展現的文字 * @param content2 點擊後展現的文字 */ public void setContent(String content1, String content2) { this.content1 = content1; this.content2 = content2; } /** * 設置是點擊後的狀態仍是點擊前的狀態 * * @param full 是否充滿背景 */ public void setFull(boolean full) { if (TextUtils.isEmpty(content1) || TextUtils.isEmpty(content2)) { throw new NullPointerException("content1 and content2 must not be null!!"); } isFull = full; txtLength = 0; invalidate(); } public boolean isFull() { return isFull; } /** * 根據模式計算高度 * * @param heightMeasureSpec */ private int measureHeight(int heightMeasureSpec) { //獲取模式 int heightMode = MeasureSpec.getMode(heightMeasureSpec); //獲取高度 int heightSize = MeasureSpec.getSize(heightMeasureSpec); int height = 0; switch (heightMode) { case MeasureSpec.EXACTLY://固定值或者match_content height = heightSize + strokeWidth * 2; break; } return height; } /** * 根據模式計算寬度 * * @param widthMeasureSpec */ private int measureWidth(int widthMeasureSpec) { //獲取模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); //獲取寬度 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int width = 0; switch (widthMode) { case MeasureSpec.EXACTLY://固定值或者match_content width = widthSize + strokeWidth * 2; break; } return width; } }
相關輔助類代碼——SizeUtils
package com.ltb.myroundtextlibrary.utils; import android.content.res.Resources; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; public class SizeUtils { private SizeUtils() { throw new UnsupportedOperationException("u can't instantiate me..."); } /** * Value of dp to value of px. * * @param dpValue The value of dp. * @return value of px */ public static int dp2px(final float dpValue) { final float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * Value of px to value of dp. * * @param pxValue The value of px. * @return value of dp */ public static int px2dp(final float pxValue) { final float scale = Resources.getSystem().getDisplayMetrics().density; return (int) (pxValue / scale + 0.5f); } /** * Value of sp to value of px. * * @param spValue The value of sp. * @return value of px */ public static int sp2px(final float spValue) { final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; return (int) (spValue * fontScale + 0.5f); } /** * Value of px to value of sp. * * @param pxValue The value of px. * @return value of sp */ public static int px2sp(final float pxValue) { final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; return (int) (pxValue / fontScale + 0.5f); } /** * Converts an unpacked complex data value holding a dimension to its final floating * point value. The two parameters <var>unit</var> and <var>value</var> * are as in {@link TypedValue#TYPE_DIMENSION}. * * @param value The value to apply the unit to. * @param unit The unit to convert from. * @return The complex floating point value multiplied by the appropriate * metrics depending on its unit. */ public static float applyDimension(final float value, final int unit) { DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); switch (unit) { case TypedValue.COMPLEX_UNIT_PX: return value; case TypedValue.COMPLEX_UNIT_DIP: return value * metrics.density; case TypedValue.COMPLEX_UNIT_SP: return value * metrics.scaledDensity; case TypedValue.COMPLEX_UNIT_PT: return value * metrics.xdpi * (1.0f / 72); case TypedValue.COMPLEX_UNIT_IN: return value * metrics.xdpi; case TypedValue.COMPLEX_UNIT_MM: return value * metrics.xdpi * (1.0f / 25.4f); } return 0; } /** * Force get the size of view. * <p>e.g.</p> * <pre> * SizeUtils.forceGetViewSize(view, new SizeUtils.OnGetSizeListener() { * Override * public void onGetSize(final View view) { * view.getWidth(); * } * }); * </pre> * * @param view The view. * @param listener The get size listener. */ public static void forceGetViewSize(final View view, final OnGetSizeListener listener) { view.post(new Runnable() { @Override public void run() { if (listener != null) { listener.onGetSize(view); } } }); } /** * Return the width of view. * * @param view The view. * @return the width of view */ public static int getMeasuredWidth(final View view) { return measureView(view)[0]; } /** * Return the height of view. * * @param view The view. * @return the height of view */ public static int getMeasuredHeight(final View view) { return measureView(view)[1]; } /** * Measure the view. * * @param view The view. * @return arr[0]: view's width, arr[1]: view's height */ public static int[] measureView(final View view) { ViewGroup.LayoutParams lp = view.getLayoutParams(); if (lp == null) { lp = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ); } int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width); int lpHeight = lp.height; int heightSpec; if (lpHeight > 0) { heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY); } else { heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); } view.measure(widthSpec, heightSpec); return new int[]{ view.getMeasuredWidth(), view.getMeasuredHeight()}; } /// // interface /// public interface OnGetSizeListener { void onGetSize(View view); } }
自定義屬性代碼
<declare-styleable name="MyRoundTextView"> <!--起始顏色--> <attr name="m_gradient_color_start" format="color|reference" /> <!--結束顏色--> <attr name="m_gradient_color_end" format="color|reference" /> <!--線條寬度--> <attr name="m_stroke_width" format="integer|dimension" /> <!--是否漸變背景充滿--> <attr name="m_is_full" format="boolean" /> </declare-styleable>
Demo的佈局代碼
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity"> <com.ltb.myroundtextlibrary.widget.MyRoundTextView android:id="@+id/btn1" android:layout_width="300dp" android:layout_height="40dp" android:layout_centerInParent="true" android:layout_gravity="center" android:layout_marginLeft="30dp" android:layout_marginTop="30dp" android:layout_marginRight="30dp" android:text="註冊" app:m_gradient_color_end="@color/colorEnd" app:m_gradient_color_start="@color/colorStart" /> <com.ltb.myroundtextlibrary.widget.MyRoundTextView android:id="@+id/btn2" android:layout_width="300dp" android:layout_height="40dp" android:layout_centerInParent="true" android:layout_gravity="center" android:layout_marginLeft="30dp" android:layout_marginTop="20dp" android:layout_marginRight="30dp" android:gravity="center" android:text="確認" app:m_gradient_color_end="@color/colorEnd" app:m_gradient_color_start="@color/colorStart" app:m_is_full="true" /> </LinearLayout>
源碼地址git
共同開發,共同進步,歡迎你們Start!!!github