android 自定義圓角button效果的實(shí)例代碼(自定義view Demo)
概述
在平時(shí)開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)碰到需要使用圓角button的情況,一般也會(huì)包括很多其他小功能,比如要在里面添加img,設(shè)置不同的圓角大小等。
針對(duì)這樣的場(chǎng)景,直接使用創(chuàng)建多個(gè)shape,定義多個(gè)xml文件也是可以實(shí)現(xiàn)的。但是如果使用非常頻繁,那么直接自定義一個(gè)就會(huì)來(lái)的非常方便。
甚至在一些情況下,不是可以用shape定義的規(guī)則圖形,比如需要用到貝塞爾曲線(xiàn)等。
如果全局需要這樣風(fēng)格的view,那么自定義一個(gè)View是非常必要的。
本文主要是個(gè)demo記錄,如有需要的讀者可以借鑒學(xué)習(xí)。
Demo
主要實(shí)現(xiàn)功能:
- 自定義圓角大小
- 支持設(shè)置leftDrawable,和自定義文字內(nèi)容(文字和img默認(rèn)居中)
- 支持點(diǎn)擊效果

源碼

RoundRadiusButton.java
/**
* author: xujiajia
* description:
* 1、drawable只有在設(shè)置textString的時(shí)候才會(huì)生效(居中效果兩個(gè)一起測(cè)量)
*/
public class RoundRadiusButton extends View {
//data
private int width = 0;
private int height = 0;
private int roundRadius = 16;
private int bgColor = Color.LTGRAY;
private boolean isTouching = false;
//img and text
private Drawable leftDrawable = null;
private int drawableWidth = 20;
private int drawableHeight = 20;
private int leftDrawablePaddingRight = 0;
private String textString;
private int textSize = 30;
private int textColor = Color.BLACK;
//onDraw
Paint paint;
Path path;
RectF rectF;
Rect rect;
public RoundRadiusButton(Context context, int width, int height) {
super(context);
this.width = width;
this.height = height;
this.setLayoutParams(new ViewGroup.LayoutParams(width, height));
this.setClickable(true);
}
public RoundRadiusButton(Context context, AttributeSet attrs) {
super(context, attrs);
getDataFromAttrs(context, attrs);
this.setClickable(true);
}
public RoundRadiusButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getDataFromAttrs(context, attrs);
this.setClickable(true);
}
private void getDataFromAttrs(Context context, AttributeSet attrs) {
if (attrs == null) {
return;
}
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.RoundRadiusButton);
roundRadius = ta.getDimensionPixelOffset(R.styleable.RoundRadiusButton_roundRadius, 16);
bgColor = ta.getColor(R.styleable.RoundRadiusButton_bgColor, Color.LTGRAY);
leftDrawable = ta.getDrawable(R.styleable.RoundRadiusButton_leftDrawable);
drawableWidth = ta.getDimensionPixelOffset(R.styleable.RoundRadiusButton_drawableWidth, 0);
drawableHeight = ta.getDimensionPixelOffset(R.styleable.RoundRadiusButton_drawableHeight, 0);
leftDrawablePaddingRight =
ta.getDimensionPixelOffset(R.styleable.RoundRadiusButton_leftDrawablePaddingRight, 0);
textString = ta.getString(R.styleable.RoundRadiusButton_textString);
textSize = ta.getDimensionPixelOffset(R.styleable.RoundRadiusButton_textSize, 0);
textColor = ta.getColor(R.styleable.RoundRadiusButton_textColor, Color.BLACK);
ta.recycle();
}
public void setRoundRadius(int roundRadius) {
this.roundRadius = roundRadius;
invalidate();
}
public void setBgColor(int bgColor) {
this.bgColor = bgColor;
invalidate();
}
public void setLeftDrawable(Drawable leftDrawable, int drawableWidth, int drawableHeight,
int paddingRight) {
this.leftDrawable = leftDrawable;
this.drawableWidth = drawableWidth;
this.drawableHeight = drawableHeight;
this.leftDrawablePaddingRight = paddingRight;
invalidate();
}
public void setTextString(String textString) {
this.textString = textString;
invalidate();
}
public void setTextColor(int textColor) {
this.textColor = textColor;
invalidate();
}
public void setTextSize(int textSize) {
this.textSize = textSize;
invalidate();
}
@Override public boolean onTouchEvent(MotionEvent event) {
if (isClickable()) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouching = true;
invalidate();
break;
case MotionEvent.ACTION_UP:
isTouching = false;
invalidate();
break;
}
}
return super.onTouchEvent(event);
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (width == 0 || height == 0) {
width = getWidth();
height = getHeight();
}
if (paint == null) {
paint = new Paint();
}
if (path == null) {
path = new Path();
}
if (rectF == null) {
rectF = new RectF();
}
if (rect == null) {
rect = new Rect();
}
paint.setColor(bgColor);
paint.setAntiAlias(true);//抗鋸齒
paint.setStrokeWidth(0);//線(xiàn)的寬度設(shè)為0,避免畫(huà)圓弧的時(shí)候部分圓弧與邊界相切
paint.setStyle(Paint.Style.FILL_AND_STROKE);
path.setFillType(Path.FillType.WINDING);
//左上圓角
path.moveTo(0, roundRadius);
rectF.set(0, 0, 2 * roundRadius,
2 * roundRadius);
path.addArc(rectF, 180, 90);
//上邊
path.lineTo(width - roundRadius, 0);
//右上圓角
rectF.set(width - roundRadius * 2, 0, width, roundRadius * 2);
path.addArc(rectF, -90, 90);
//右邊
path.lineTo(width, height - roundRadius);
//右下圓角
rectF.set(width - roundRadius * 2, height - roundRadius * 2, width,
height);
path.addArc(rectF, 0, 90);
//下邊
path.lineTo(roundRadius, height);
//左下圓角
rectF.set(0, height - roundRadius * 2, 2 * roundRadius,
height);
path.addArc(rectF, 90, 90);
//左邊
path.lineTo(0, roundRadius);
path.close();
canvas.drawPath(path, paint);
if (isTouching) {
paint.setColor(getContext().getResources().getColor(R.color.black_tran_30));
canvas.drawPath(path, paint);
}
//填充背景中間空白的部分
path.moveTo(0, roundRadius);
path.lineTo(width - roundRadius, 0);
path.lineTo(width, height - roundRadius);
path.lineTo(roundRadius, height);
path.close();
canvas.drawPath(path, paint);
if (isTouching) {
paint.setColor(getContext().getResources().getColor(R.color.black_tran_30));
canvas.drawPath(path, paint);
}
//text, drawable兩個(gè)一起計(jì)算位置
if (!TextUtils.isEmpty(textString)) {
paint.setStrokeWidth(1.5f);
paint.setColor(textColor);
paint.setTextSize(textSize);
rect.setEmpty();
paint.getTextBounds(textString, 0, textString.length(), rect);
float leftBitmap = 0;
float topBitmap = 0;
if (leftDrawable != null) {
if (leftDrawable != null) {
leftBitmap = (1.0f * width - drawableWidth - rect.width() - leftDrawablePaddingRight) / 2;
topBitmap = (1.0f * height - drawableHeight) / 2;
leftDrawable.setBounds((int) leftBitmap, (int) topBitmap,
(int) (leftBitmap + drawableWidth),
(int) (topBitmap + drawableHeight));
leftDrawable.draw(canvas);
}
}
float textX = 0;
float textY =
1.0f * height / 2 + paint.getTextSize() / 2 - paint.getFontMetrics().descent / 2;
if (leftBitmap == 0 && topBitmap == 0) {
textX = width / 2 - rect.width() / 2;
} else {
textX = leftBitmap + drawableWidth + leftDrawablePaddingRight;
}
canvas.drawText(textString, textX, textY, paint);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private LinearLayout llContainer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
llContainer = findViewById(R.id.ll_container);
RoundRadiusButton roundRadiusButton = new RoundRadiusButton(this, 500, 200);
roundRadiusButton.setBgColor(Color.LTGRAY);
roundRadiusButton.setRoundRadius(40);
//text
roundRadiusButton.setTextString("testtesttest");
roundRadiusButton.setTextColor(Color.WHITE);
roundRadiusButton.setTextSize(40);
//drawable
roundRadiusButton.setLeftDrawable(getResources().getDrawable(R.mipmap.ic_launcher), 60, 60, 80);
roundRadiusButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
Toast.makeText(MainActivity.this, "testest", Toast.LENGTH_LONG).show();
}
});
roundRadiusButton.setClickable(false);
llContainer.addView(roundRadiusButton);
}
}
activity_main.xml
<?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:id="@+id/ll_container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#868684" android:gravity="center" android:orientation="vertical" tools:context=".MainActivity" > <com.example.newbuttiontest.RoundRadiusButton android:layout_width="300dp" android:layout_height="200dp" app:bgColor="#FFEB3B" app:drawableHeight="18dp" app:drawableWidth="18dp" app:leftDrawable="@mipmap/ic_launcher" app:leftDrawablePaddingRight="5dp" app:roundRadius="30dp" app:textColor="#FF4329" app:textSize="16dip" app:textString="testtesttest" /> </LinearLayout>
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="RoundRadiusButton"> <attr name="roundRadius" format="dimension" /> <attr name="bgColor" format="color" /> <attr name="leftDrawable" format="reference" /> <attr name="leftDrawablePaddingRight" format="dimension" /> <attr name="drawableWidth" format="dimension" /> <attr name="drawableHeight" format="dimension" /> <attr name="textString" format="string" /> <attr name="textSize" format="dimension" /> <attr name="textColor" format="color" /> </declare-styleable> </resources>
colors.xml
<resources> <color name="black_tran_30">#30000000</color> </resources>
總結(jié)
以上所述是小編給大家介紹的android 自定義圓角button效果的實(shí)例代碼,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章
android studio 4.0 新建類(lèi)沒(méi)有修飾符的方法
這篇文章主要介紹了android studio 4.0 新建類(lèi)沒(méi)有修飾符的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Android計(jì)時(shí)器控件Chronometer應(yīng)用實(shí)例
這篇文章主要為大家詳細(xì)介紹了Android計(jì)時(shí)器控件Chronometer應(yīng)用實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
android實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)效果的代碼解析
這篇文章主要介紹了android實(shí)現(xiàn)滑動(dòng)標(biāo)簽頁(yè)效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
詳解Android Material Design自定義動(dòng)畫(huà)的編寫(xiě)
這篇文章主要介紹了詳解Android Material Design自定義動(dòng)畫(huà)的編寫(xiě),其中對(duì)Activity的過(guò)渡動(dòng)畫(huà)進(jìn)行了重點(diǎn)講解,需要的朋友可以參考下2016-04-04
Android使用HttpURLConnection實(shí)現(xiàn)網(wǎng)絡(luò)訪(fǎng)問(wèn)流程
早些時(shí)候其實(shí)我們都習(xí)慣性使用HttpClient,但是后來(lái)Android6.0之后不再支持HttpClient,需要添加Apache的jar才行,所以,就有很多開(kāi)發(fā)者放棄使用HttpClient了,HttpURLConnection畢竟是標(biāo)準(zhǔn)Java接口(java.net) ,適配性還是很強(qiáng)的2022-12-12
Android自定義View實(shí)現(xiàn)可以拖拽的GridView
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)可以拖拽的GridView,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
Android筆記之:App模塊化及工程擴(kuò)展的應(yīng)用
這篇文章是android開(kāi)發(fā)人員的必備知識(shí),是我特別為大家整理和總結(jié)的,不求完美,但是有用2013-04-04
Android開(kāi)發(fā)事件處理的代碼如何寫(xiě)手摸手教程
這篇文章主要為大家介紹了Android開(kāi)發(fā)事件處理的代碼如何寫(xiě)手摸手教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02
Android開(kāi)發(fā)必備技巧之高效字符串篩選
在開(kāi)發(fā)過(guò)程中或多或少都要使用一些方法去篩選符合我們要求的字符串,所以下面我們就來(lái)介紹一些在開(kāi)發(fā)工作中常用到的字符串篩選方法,讓大家都能掌握高效的字符串篩選技巧吧2023-06-06

