android开发自定义动态Button

package com.example.mybutton;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;

public class MyButton extends Button {

	private Paint mTextPaint, mPaint;
	private String mText;
	private int mAscent;
	private Shader mShader;
	private Matrix mMatrix = new Matrix();// 一个3*3的矩阵,通过该矩阵可以完成平移旋转
	private float mStart;//下一次画椭圆的起点
	private float mSweep;// 用来表示绘制的角度,也就是扫描(抹掉)的角度
	private float mRotate;// 用来表示闪动的频率
	private static final float SWEEP_INC = 2;
	private static final float START_INC = 15;

	/**
	 * 2个构造函数初始化Paint画笔,以及padding
	 * 
	 * @param context
	 */
	public MyButton(Context context) {
		super(context);
		initLabelView();
	}

	public MyButton(Context context, AttributeSet attrs) {
		super(context, attrs);
		initLabelView();
	}

	private final void initLabelView() {
		mTextPaint = new Paint();
		mTextPaint.setAntiAlias(true);
		mTextPaint.setTextSize(16);
		mTextPaint.setColor(0xff000000);
		setPadding(15, 15, 15, 15);
		mPaint = new Paint();
		mPaint.setAntiAlias(true);
		mPaint.setStrokeWidth(4);
		mPaint.setAntiAlias(true);// 抗锯齿,图像边缘稍微清晰一点,没有锯齿,是图像的边缘
		mPaint.setStyle(Paint.Style.STROKE);
		// colors The colors to be distributed between around the
		// center,第三个参数表示圆圈的颜色变化,第一个颜色是主要的颜色
		// 最后一个颜色会闪动,中间的颜色不显示
		mShader = new SweepGradient(this.getMeasuredWidth(),
				this.getMeasuredHeight(), new int[] { Color.GREEN,
						Color.DKGRAY, Color.BLUE }, null);
		mPaint.setShader(mShader);// 设置颤抖效果
	}

	/**
	 * setText和setTextSize都可能会改变大小,这就需要requestLayout
	 * setText和setTextSize、setTextColor调用后都需要重绘
	 * 
	 * @param text
	 */
	public void setText(String text) {
		mText = text;
		requestLayout();
		invalidate();
	}

	public void setTextSize(int size) {
		mTextPaint.setTextSize(size);
		requestLayout();
		invalidate();
	}

	public void setTextColor(int color) {
		mTextPaint.setColor(color);
		invalidate();
	}

	// 自定义视图关键一步,必须调用setMeasuredDimension(int width, int
	// height)来存储测量得到的宽度和高度值,如果没有这么去做会触发异常IllegalStateException。

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(measureWidth(widthMeasureSpec),// dimension:尺寸
				measureHeight(heightMeasureSpec));
	}

	/**
	 * 获取宽度
	 * 
	 * @param measureSpec
	 * @return
	 */
	private int measureWidth(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);
		if (specMode == MeasureSpec.EXACTLY) {
			// we were told how big to be.
			result = specSize;
		} else {
			// measure the text
			// 这是UNSPECIFIED情况下的result
			result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
					+ getPaddingRight();
			if (specMode == MeasureSpec.AT_MOST) {// at most至多的意思
				result = Math.min(result, specSize);// 使用的不能超过specSize,如果小于specSize就想用多少用多少
			}
		}

		return result;
	}

	private int measureHeight(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		mAscent = (int) mTextPaint.ascent();
		if (specMode == MeasureSpec.EXACTLY) {
			// we were told how big to be
			result = specSize;
		} else {
			// Measure the Text(beware: ascent is a negative number)
			result = (int) (mTextPaint.descent() - mAscent) + getPaddingTop()
					+ getPaddingBottom();
			if (specMode == MeasureSpec.AT_MOST) {
				Log.v("Measure Height", "At Most Height:" + specSize);
				result = Math.min(specSize, result);
			}
		}
		return result;
	}

	private void drawArcs(Canvas canvas, RectF oval, boolean useCenter,
			Paint paint) {
		canvas.drawArc(oval, mStart, mSweep, useCenter, paint);// mStart和mSweep都没有初始化就是0咯
	}

	// onDraw方法的调用后除了开始调用还会在每次的click后调用,还会在invalidate()里面调用,所以invalidate和onDraw一直互相调用
	@Override
	protected void onDraw(Canvas canvas) {
		measure(0, 0);//由于调用过this.getMeasuredWidth所以得先测量下
		mMatrix.setRotate(mRotate, this.getMeasuredWidth() / 2,
				this.getMeasuredHeight() / 2);// 设置闪动的的频率和中心
		mShader.setLocalMatrix(mMatrix);// mShader最后会被设置到mPaint上
		mRotate += 10;// 设置闪动的频率,越来越快直到360
		if (mRotate >= 360) {
			mRotate = 0;
		}
		RectF drawRect = new RectF();//容纳4个点的容器
		drawRect.set(this.getWidth() - mTextPaint.measureText(mText),
				(this.getHeight() - mTextPaint.getTextSize()) / 2,
				mTextPaint.measureText(mText),
				this.getHeight()
						- (this.getHeight() - mTextPaint.getTextSize()) / 2);
		drawArcs(canvas, drawRect, false, mPaint);// 这里该画笔控制每次画多少逐渐的画完360
		mSweep += SWEEP_INC;
		if (mSweep > 360) {
			mSweep -= 360;
			mStart += START_INC;// 每次移动15等24次移动一周,此时已经画了24个椭圆
			if (mStart > 360) {
				mStart -= 360;
			}
		}
		if (mSweep > 180) {
			canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent,
					mTextPaint);
		}
		invalidate();
		/*if(b){
			b=false;
			invalidate();
		}*/
	}
	boolean b=true;
}

上面的Button这样设置到布局文件里面

    <com.example.mybutton.MyButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/mybutton1"/>

在主Activity里面:

mButton=(MyButton) findViewById(R.id.mybutton1);
		mButton.setText("Custom Button");
		mButton.setTextSize(40f);
		mButton.setTextColor(Color.RED);


于是我们可以看见一个动态的Button,如何让它慢点或者停止呢,只需要不让onDraw里面持续调用invalidate就就行了

注释掉invalidate,然后取消下面if(){}外面的注释,运行一下,每次点击后就重新invalidate一次,这样就看到慢点的Button了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值