因为项目需要只有边框和文字渐变效果得按钮,尝试过用drawable文件设置,发现只能设置全背景渐变效果,也懒得用其他方式,就自己动手画了一个,画完之后就把全背竟的也给加上了,因为这个项目类似这种的按钮还不少,避免了挨个去创建drawable文件了。当我写完之后,微信就更新了8.0发现这个按钮跟微信8.0的状态按钮挺像,就起了这么一个标题
最开始画这个控件的时候,继承的是View,自己用画笔去绘制文字,发现居中一直有问题,算了一下午的文字居中发现没有任何屌用,后来小伙伴跟我说,那你就继承TextView,然后直接设置文字居中不就好了,当时感觉自己的智商被人摁在地上摩擦。。。。。
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;
}
}
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 unit and value
* 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.
* e.g.
*
* SizeUtils.forceGetViewSize(view, new SizeUtils.OnGetSizeListener() {
* Override
* public void onGetSize(final View view) {
* view.getWidth();
* }
* });
*
*
* @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>
<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>
源码地址
共同开发,共同进步,欢迎大家Start!!!