android 自定義圓角button(自定義View Demo)

概述

在平時開發過程中經常會碰到需要使用圓角button的情況,一般也會包括很多其他小功能,比如要在裏面添加img,設置不同的圓角大小等。
針對這樣的場景,直接使用創建多個shape,定義多個xml文件也是可以實現的。但是如果使用非常頻繁,那麼直接自定義一個就會來的非常方便。

甚至在一些情況下,不是可以用shape定義的規則圖形,比如需要用到貝塞爾曲線等。
如果全局需要這樣風格的view,那麼自定義一個View是非常必要的。

本文主要是個demo記錄,如有需要的讀者可以借鑑學習。

Demo

主要實現功能:

  1. 自定義圓角大小
  2. 支持設置leftDrawable,和自定義文字內容(文字和img默認居中)
  3. 支持點擊效果

源碼

RoundRadiusButton.java

/**
 * author: xujiajia
 * description:
 * 1、drawable只有在設置textString的時候纔會生效(居中效果兩個一起測量)
 */
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:
        case MotionEvent.ACTION_CANCEL:
          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();
    }else {
      path.reset();
    }
    if (rectF == null) {
      rectF = new RectF();
    }
    if (rect == null) {
      rect = new Rect();
    }

    paint.setColor(bgColor);
    paint.setAntiAlias(true);//抗鋸齒
    paint.setStrokeWidth(0);//線的寬度設爲0,避免畫圓弧的時候部分圓弧與邊界相切
    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();

    //填充背景中間空白的部分
    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兩個一起計算位置
    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);
    }
  }
}

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>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章