Android安卓自定义圆角菜单控件,解决自定义xml,书写一大堆代码的烦恼,轻松编程

1  先看效果图


2 背景

项目的设计师常常要用到一些圆角的控件,也喜欢用圆角菜单,圆角菜单实现起来本不复杂,但纠结的事,每次都要写一大堆的繁琐的XML,没有营养的代码,至此自定义一个圆角控件的想法产生了。

3 技术要领

主要用到了 canvas.drawRoundRect、canvas.drawRect、canvas.drawLine等方法以及自定义视图,自定义属性等

4 怎么实现的

A 在value目录下att.xml 里面定义属性

    <!-- 圆角矩形可以选择的选择器 -->
    <declare-styleable name="ShapeCornerSelectView">
        <attr name="appsBorder" format="boolean" />
        <!-- 是否有边框,默认有 -->
        <attr name="appsDivider" format="boolean" />
        <!-- 是否有分割线,默认无 -->
        <attr name="appsDividerColor" format="boolean" />
        <!-- 分割线颜色 -->
        <attr name="appsBorderWidth" format="dimension" />
        <!-- 边框线条的粗细 -->
        <attr name="appsBorderColor" format="color" />
        <!-- 边框线条的颜色 -->
        <attr name="appsBgColor" format="color" />
        <!-- 背景的颜色 (默认) -->
        <attr name="appsBgColorSelect" format="color" />
        <!-- 背景的颜色(选中) -->
        <attr name="appsRadius" format="dimension" />
        <!-- 圆角度数 -->
        <attr name="appsTextColorSelect" format="color" />
        <!-- 文本颜色(选中) -->
        <attr name="appsTextSizeSelect" format="dimension" />
        <!-- 文本字的大小(选中) -->
        <attr name="appsTextColor" format="color" />
        <!-- 文本颜色(默认) -->
        <attr name="appsTextSize" format="dimension" />
        <!-- 文本颜色(默认) -->
    </declare-styleable>

B 定义对应属性所对应的控件变量

	private int textColorSelect = Color.WHITE;// 选中的字体的颜色

	private int textSize = 22;// 字体大小

	private int bgColorSelect = Color.RED;// 选中的背景颜色

	private int textColor = bgColorSelect;// 字体颜色

	private int bgColor = Color.TRANSPARENT;// 没选中的颜色是透明的

	private int mRadius = 5;// 圆角矩形半径

	private int borderColor = bgColorSelect;// 边框的颜色

	private int borderWidth = 2;// 边框的宽度

	private boolean isDivider = false;// 是否有分割线

	private int dividerColor = bgColorSelect;// 分割线的颜色

	private boolean isBorder = true;// 是否有边框,默认有

C 关连变量与属性

		TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ShapeCornerSelectView);

		// bgSelectColor颜色 默认与不选中字色,边框色一样,默认选中字是白色的,不选中时是背景颜色,bgColor默认是透明的,
		// 选中的背景颜色
		bgColorSelect = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBgColorSelect, bgColorSelect);
		textColor = dividerColor = borderColor = bgColorSelect;

		// 未选中的字体颜色
		textColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsTextColor, textColor);
		// 选中的字体的颜色
		textColorSelect = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsTextColorSelect, textColorSelect);
		// 字体大小
		textSize = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsTextSize, textSize);

		// 没选中的颜色是透明的
		bgColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBgColor, bgColor);
		// 圆角矩形半径
		mRadius = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsRadius, mRadius);
		// 没选中的颜色是透明的
		borderColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBorderColor, borderColor);
		// 边框的宽度
		borderWidth = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsBorderWidth, borderWidth);
		// 是否有分割线
		isDivider = mTypedArray.getBoolean(R.styleable.ShapeCornerSelectView_appsDivider, isDivider);
		// 分割线的颜色
		dividerColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsDividerColor, dividerColor);
		// 是否有边框
		isBorder = mTypedArray.getBoolean(R.styleable.ShapeCornerSelectView_appsBorder, isBorder);
		mTypedArray.recycle();

D 添加所有Button

	private void addAllButtons() {
		this.removeAllViews();
		int count = 0;
		for (String string : arrStrings) {
			TextView textView = new TextView(getContext());
			this.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
			textView.setOnClickListener(this);
			// 方便外面使用
			textView.setId(count++);
			textView.setText(string);
			LayoutParams ll = ((LayoutParams) textView.getLayoutParams());
			ll.width = 0;
			ll.weight = 1;
			textView.setGravity(Gravity.CENTER);
		}
	}

5 附所有实现过程

package com.example.tttttttt;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.example.tttttttt.R;

/***
 * 圆角条形菜单
 */
public class ShapeCornerSelectView extends LinearLayout implements OnClickListener {

	Paint mPaint;

	// 可定义自定义的

	private int textColorSelect = Color.WHITE;// 选中的字体的颜色

	private int textSize = 22;// 字体大小

	private int bgColorSelect = Color.RED;// 选中的背景颜色

	private int textColor = bgColorSelect;// 字体颜色

	private int bgColor = Color.TRANSPARENT;// 没选中的颜色是透明的

	private int mRadius = 5;// 圆角矩形半径

	private int borderColor = bgColorSelect;// 边框的颜色

	private int borderWidth = 2;// 边框的宽度

	private boolean isDivider = false;// 是否有分割线

	private int dividerColor = bgColorSelect;// 分割线的颜色

	private boolean isBorder = true;// 是否有边框,默认有

	private RectF rectf = new RectF();

	public static int dip2px(Context context, float dpValue) {
		final float scale = context.getResources().getDisplayMetrics().density;
		return (int) (dpValue * scale + 0.5f);
	}

	public static int getDimen720Px(Context context, int dimen) {
		float dp = dimen * 1080f / 720 / 3;
		return dip2px(context, dp);
	}

	public ShapeCornerSelectView(Context context, AttributeSet attrs) {
		super(context, attrs);
		setOrientation(HORIZONTAL);// 水平条子
		setWillNotDraw(false);// 解决linearlayout不绘制问题

		// 转换单位
		textSize = getDimen720Px(context, textSize);
		mRadius = getDimen720Px(context, mRadius);
		borderWidth = getDimen720Px(context, borderWidth);

		TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ShapeCornerSelectView);

		// bgSelectColor颜色 默认与不选中字色,边框色一样,默认选中字是白色的,不选中时是背景颜色,bgColor默认是透明的,
		// 选中的背景颜色
		bgColorSelect = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBgColorSelect, bgColorSelect);
		textColor = dividerColor = borderColor = bgColorSelect;

		// 未选中的字体颜色
		textColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsTextColor, textColor);
		// 选中的字体的颜色
		textColorSelect = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsTextColorSelect, textColorSelect);
		// 字体大小
		textSize = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsTextSize, textSize);

		// 没选中的颜色是透明的
		bgColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBgColor, bgColor);
		// 圆角矩形半径
		mRadius = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsRadius, mRadius);
		// 没选中的颜色是透明的
		borderColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsBorderColor, borderColor);
		// 边框的宽度
		borderWidth = mTypedArray.getDimensionPixelSize(R.styleable.ShapeCornerSelectView_appsBorderWidth, borderWidth);
		// 是否有分割线
		isDivider = mTypedArray.getBoolean(R.styleable.ShapeCornerSelectView_appsDivider, isDivider);
		// 分割线的颜色
		dividerColor = mTypedArray.getColor(R.styleable.ShapeCornerSelectView_appsDividerColor, dividerColor);
		// 是否有边框
		isBorder = mTypedArray.getBoolean(R.styleable.ShapeCornerSelectView_appsBorder, isBorder);
		mTypedArray.recycle();

		// 初始化画笔
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
	}

	/**
	 * 较正圆角矩形
	 * 
	 * @param rectF
	 */
	private void changeRectF(RectF rectF) {
		int half = borderWidth / 2;
		rectF.top += half;
		rectF.left += half;
		rectF.bottom -= half;
		rectF.right -= half;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 没有初始化完成,则返回
		if (width == 0 || buttonNum == 0) {
			return;
		}
		// 画背景
		drawBackground(canvas);
		// 画边框,透明则不画
		drawBorder(canvas);
		// 画分隔线
		drawDivider(canvas);
		// 画选中
		drawSelect(canvas);
	}

	// 画背景,透明则不画
	private void drawBackground(Canvas canvas) {
		if (bgColor != Color.TRANSPARENT) {
			mPaint.setColor(bgColor);
			mPaint.setStyle(Style.FILL);
			drawFullRoundRect(canvas);
		}
	}

	// 画边框,透明则不画
	private void drawBorder(Canvas canvas) {
		if (isBorder && borderColor != Color.TRANSPARENT) {
			mPaint.setColor(borderColor);
			mPaint.setStyle(Style.STROKE);
			mPaint.setStrokeWidth(borderWidth);
			drawFullRoundRect(canvas);
		}
	}

	// 画选中
	private void drawSelect(Canvas canvas) {
		if (bgColorSelect != Color.TRANSPARENT) {
			mPaint.setStyle(Style.FILL);
			mPaint.setColor(bgColorSelect);
			float piece = width / buttonNum;
			// 线宽一半
			rectf.left = piece * currentIndex;
			rectf.top = 0;
			rectf.right = piece * (currentIndex + 1); // 右边
			rectf.bottom = height; // 下边
			// 索引的第一个及最后一个是圆角矩形填充
			if (currentIndex == 0 || currentIndex == buttonNum - 1) {
				changeRectF(rectf);// 修正
				if (currentIndex == 0) {
					rectf.right += borderWidth / 2;// 修正
					canvas.drawRoundRect(rectf, mRadius, mRadius, mPaint);
					rectf.left = rectf.right - mRadius;
				} else {
					rectf.left -= borderWidth / 2;// 修正
					canvas.drawRoundRect(rectf, mRadius, mRadius, mPaint);
					rectf.right = rectf.left + mRadius;
				}
				// 填充圆角矩形成直角
				canvas.drawRect(rectf, mPaint);

			} else {
				// 画直角
				canvas.drawRect(rectf, mPaint);
			}
		}
	}

	// 画分隔线
	private void drawDivider(Canvas canvas) {
		if (isDivider && dividerColor != Color.TRANSPARENT) {
			mPaint.setColor(dividerColor);
			float piece = width / buttonNum;
			for (int i = 1; i < buttonNum; i++) {
				canvas.drawLine(i * piece, borderWidth, i * piece, height - borderWidth, mPaint);
			}
		}
	}

	// 画全屏的圆角矩形
	private void drawFullRoundRect(Canvas canvas) {
		rectf.left = 0;
		rectf.top = 0;
		rectf.right = width;
		rectf.bottom = height;
		if (mPaint.getStyle() == Style.STROKE) {// 画空心时需要减掉线的宽度的一半
			changeRectF(rectf);
		} else {// 实心
			if (isBorder && borderColor != Color.TRANSPARENT) {// 有边线,向内部多画一点
				changeRectF(rectf);
			}
		}
		canvas.drawRoundRect(rectf, mRadius, mRadius, mPaint); // 绘制圆角矩形
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		width = w;
		height = h;
	}

	int width, height;
	private OnClickListener clickListener;
	// 选中的String
	private String arrStrings[];
	private int currentIndex = -1; // 当前哪个被选中
	private int buttonNum = 0;// 按钮的数量

	// 初始化所有的button
	public void initButtons(String arr[], OnClickListener clickListener) {
		this.clickListener = clickListener;
		this.arrStrings = arr;
		this.buttonNum = arr.length;
		// 添加BUTTON,并初始化事件
		addAllButtons();
		// 设置button选中,默认第一个
		setCurrentIndex(0);
	}

	/***
	 * 添加所有的button
	 */
	private void addAllButtons() {
		this.removeAllViews();
		int count = 0;
		for (String string : arrStrings) {
			TextView textView = new TextView(getContext());
			this.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
			textView.setOnClickListener(this);
			// 方便外面使用
			textView.setId(count++);
			textView.setText(string);
			LayoutParams ll = ((LayoutParams) textView.getLayoutParams());
			ll.width = 0;
			ll.weight = 1;
			textView.setGravity(Gravity.CENTER);
		}
	}

	/***
	 * 设置第几个BUTTON 被选中
	 * 
	 * @param index
	 */
	public void setCurrentIndex(int index) {
		if (currentIndex != index) {
			if (index >= 0 && index < buttonNum) {// 合法性检查
				currentIndex = index;
				for (int i = 0; i < buttonNum; i++) {
					TextView textView = (TextView) this.getChildAt(i);
					textView.setEnabled(i != currentIndex);// 选中的无法再点击
					textView.setTextColor(i == currentIndex ? textColorSelect : textColor);
				}
				invalidate();// 重画背景
			}
		}
	}

	@Override
	public void onClick(View arg0) {
		int index = arg0.getId();
		setCurrentIndex(index);
		if (clickListener != null)
			clickListener.onClick(arg0);
	}

	/***
	 * 获得当前选项的文字
	 * 
	 * @return
	 */
	public String getCurrentButtonText() {
		return arrStrings[currentIndex];
	}

	/**
	 * 获得当前索引
	 * 
	 * @return
	 */
	public int getCurrentIndex() {
		return currentIndex;
	}

}

后记

写程序不能重复造轮子,一直原地踏步,做同样的事。只有提升生产力,提高劳动生产效率,才能收到额外的收益(高中政治课本里的一句话)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值