自定义view之----自定义button

前言:

唉,学习自定义view已经很长时间了,很早就想写自定义view这类的博客,这样一来不仅能够对知识的梳理与巩固还能帮助他人。计划再好不如即时行动更为有效,所以趁着周末赶紧把这个月的计划完成先。


ok,废话少说(貌似好像前面的都是废话~ 额’),切入正题。

正题:

一般应用中按钮(Button)都会结合自己应用的主题风格来自定义,如:qq,微博,支付宝的登陆按钮,这里就不贴图了,它们登陆按钮的共同特点都是圆角,不同的是背景颜色不同而已。如果要实现类似的效果,我想说的是 so easy!那么,如果你看到了这里,不管你会还是不会,这bi我还是要装一下的。haha~

实现方式有两种:

方法一:

只需要自定义背景属性就能实现

首先看下效果图,有边框的,由于是静态图所以无法看到点击的效果

这里写图片描述

好了,开始贴代码了

xml文件布局代码:
style=”?android:attr/borderlessButtonStyle”//这一行代码是5.0以上版本去掉Button自带阴影效果的方法

<Button
                style="?android:attr/borderlessButtonStyle"
                android:layout_marginTop="50dp"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:background="@drawable/button_click_enabled"
                android:layout_gravity="center"
                android:text="只设置上面两个角为圆角"/>
            <Button
                android:layout_margin="20dp"
                android:layout_width="200dp"
                style="?android:attr/borderlessButtonStyle"
                android:layout_height="wrap_content"
                android:background="@drawable/button_click_enabled_5"
                android:layout_gravity="center"
                android:textColor="#fff"
                android:textSize="15dp"
                android:text="圆角"/>

button_click_enabled.xml 文件:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/button_click_unchecked" android:state_pressed="false"></item>
    <item android:drawable="@drawable/button_click_checked" android:state_pressed="true"></item>
</selector>

selector选择器的意思,顾名思义就算你没学过你也已经知道它是干什么的了吧。默认显示背景@drawable/button_click_unchecked,当只有按住按钮(android:state_pressed=”true”时)才会显示 背景@drawable/button_click_checked

button_click_unchecked.xml文件:
(复制代码后删掉注释)

扫描二维码关注公众号,回复: 2985306 查看本文章
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorAccent"//控件颜色
    />
    <corners
        android:bottomLeftRadius="0dp"//左下角设置圆角半径为0
        android:bottomRightRadius="0dp"//右下角设置圆角半径为0
        android:topLeftRadius="20dp"//左上角设置圆角半径为20
        android:topRightRadius="20dp" //右上角设置圆角半径为20
        />
    <stroke
        android:width="2px"//边框宽
        android:color="#2443D0"//边框颜色
         />
</shape>

button_click_checked.xml文件:

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#fe3"></solid>

    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="20dp"
        android:topRightRadius="20dp" />
    <stroke
        android:width="2px"
        android:color="#2443D0" />
</shape>

ok,
就这么简单。
偷偷告诉你不只是button,其他控件也可以这么干,自己去发掘吧!

方法二:

下面我要讲的才算是自定义view,这种实现方式就比较高大上了,首先你需要对自定义view的知识有一定的了解,不了解也没关系,有看不懂的地方请自行百度。如果方法一能实现需求,但你觉得太low了,那么不要走开(装逼模式已开启~)。

同样,放张效果图:
这里写图片描述

实现思路:
系统Button是继承Textview的,所以自定义的view也继承Textview。
按照步骤:
1.创建类cButton继承Textview

2.设置自定义属性(在res/values/styles.xml中):

 <declare-styleable name="cButton">
        <attr name="internalcolor" format="color" />//内部填充颜色
        <attr name="clickedColor" format="color" />//点击后颜色
        <attr name="bordercolor" format="color" />//边框颜色
        <attr name="textcolor" format="color" />//文字颜色
        <attr name="textsize" format="dimension" />//文字大小
        <attr name="textstr" format="string" />//文字
        <attr name="enablerd" format="boolean" />//是否可点击
        <attr name="angletype" format="integer">//圆角类型
            <enum name="anglecirarc" value="1" />//圆弧形
            <enum name="anglecir" value="2" />//小圆角
        </attr>
    </declare-styleable>

3.在cButton类中对自定义属性进行解析,解析时设置默认值

 public cButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.cButton);
        enabler = ta.getBoolean(R.styleable.cButton_enablerd, true);//是否可点击
        AngleType = ta.getInt(R.styleable.cButton_angletype, 1);//圆角类型
        clicked_color = ta.getColor(R.styleable.cButton_clickedColor, Color.parseColor("#6F4A4C58"));//点击后的颜色
        border_color = ta.getColor(R.styleable.cButton_bordercolor, Color.parseColor("#40000000"));//边框颜色
        interna_Color = ta.getColor(R.styleable.cButton_internalcolor, Color.parseColor("#FF4A4C58"));//背景颜色
        text_Color = ta.getColor(R.styleable.cButton_textcolor, Color.BLACK);//文字颜色
        text_Size = ta.getDimension(R.styleable.cButton_textsize, 40);//文字大小
        text = ta.getString(R.styleable.cButton_textstr);//文字
    }

4.逻辑处理绘制图形:

重点说一下,文字居中绘制:看这里http://blog.csdn.net/u014702653/article/details/51985821
宽=控件宽度/2 - 文字宽度/2;
高=控件高度/2 + 文字高度/2;
tPaint.measureText(text);//文字宽度
Paint.FontMetricsInt fm = tPaint.getFontMetricsInt();
fm.bottom - fm.top//文字高度
canvas.drawText(“字符串文字”, 宽, 高, tPaint);// 绘制文字

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//此处省略n条代码
canvas.drawText(text, startX, startY, tPaint);//绘制文字       
canvas.drawRoundRect(rectF, rx, ry, Paint);//绘制圆角矩形
}

5.(能够绘制正常图像之后)定义点击回调接口,和触发点击的方法

public boolean onTouchEvent(MotionEvent event) {
  //cListener.click(cButton.this);//触发点击事件
   //此处省略n条代码
   return true;
}
 /**
     * 定义接口
     */
    public interface OncButtonListener {

        void click(View v);
    }
    /**
     * 监听回调方法
     */
    public void setcButtonListener(OncButtonListener listener) {

        cListener = listener;
    }

6.定义设置属性方法:
每个方法中都必须有invalidate()方法,不然设置无效

    /**
     * 设置是否可点击
     */
    public void setEnabler(boolean enabler) {

        this.enabler = enabler;
        if (enabler) {
            set_Color = interna_Color;
        } else {//
            set_Color = clicked_color;
        }
         invalidate();//重新绘制
    }

    /**
     * 设置文字
     */
    public void setText(String text) {
        this.text = text;
        invalidate();//重绘
    }

   //省略

完成。

下面贴具体代码:

cButton类:

/**
 * Created by xxf on 2017/8/19.
 */

public class cButton extends TextView {
    /* 画笔 */
    private Paint mPaint;//   填充
    private Paint bPaint;//   边框
    private Paint tPaint;//绘制文字

    private int mWith, mHeight;//宽、高
    private Rect oRect;//
    private String text;//文字
    private int clicked_color;//点击后的颜色
    private int interna_Color;//填充颜色
    private int set_Color;//设置颜色
    private int text_Color;//文字颜色
    private float text_Size;//字体大小
    private OncButtonListener cListener;//点击监听
    private Context mContext;
    private int border_color;
    private boolean enabler;//设置是否可点击
    private int AngleType;//圆角样式

    public cButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.cButton);
        enabler = ta.getBoolean(R.styleable.cButton_enablerd, true);//是否可点击
        AngleType = ta.getInt(R.styleable.cButton_angletype, 1);//圆角类型
        clicked_color = ta.getColor(R.styleable.cButton_clickedColor, Color.parseColor("#6F4A4C58"));//点击后的颜色
        border_color = ta.getColor(R.styleable.cButton_bordercolor, Color.parseColor("#40000000"));//边框颜色
        interna_Color = ta.getColor(R.styleable.cButton_internalcolor, Color.parseColor("#FF4A4C58"));//背景颜色
        if (enabler) {
            set_Color = interna_Color;
        } else {//
            set_Color = clicked_color;
        }

        text_Color = ta.getColor(R.styleable.cButton_textcolor, Color.BLACK);//文字颜色
        text_Size = ta.getDimension(R.styleable.cButton_textsize, 40);//文字大小
        text = ta.getString(R.styleable.cButton_textstr);//文字
    }

    /*用于测量视图的大小的*/
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWith = MeasureSpec.getSize(widthMeasureSpec);    //取出宽度的确切数值
        mHeight = MeasureSpec.getSize(heightMeasureSpec);    //取出高度的确切数值

    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        init();
        //  Log.e(TAG, "onTouchEvent: " + interna_Color);
//        RectF rectF = new RectF(0 + 10, 0 + 10, mWith - 10, mHeight - 10);
        if (AngleType == 1) {
            // Log.e(TAG, "onDraw: " + 1);
            RectF rectF = new RectF(0 + 10, 0 + 10, mWith - 10, mHeight - 10);
            canvas.drawRoundRect(rectF, mHeight / 2, mHeight / 2 + 30, mPaint);
            canvas.drawRoundRect(rectF,mHeight / 2, mHeight / 2 + 30, bPaint);//边框
        } else if (AngleType == 2) {
            // Log.e(TAG, "onDraw: " + 2);
            RectF rectF = new RectF(0 + 20, 10, mWith - 20, mHeight - 10);
            canvas.drawRoundRect(rectF, mHeight / 9, mHeight / 9, mPaint);
            canvas.drawRoundRect(rectF, mHeight / 9, mHeight / 9, bPaint);
//        canvas.drawRoundRect(rectF, mHeight / 4, mHeight / 4, bPaint);//边框
        }


        // canvas.drawText("123",mWith/2,mHeight/2,tPaint);
        /*
         * 控件宽度/2 - 文字宽度/2
         */
        float  v=  tPaint.measureText(text);//文字宽度
        float startX = getWidth() / 2 - v / 2;

        /*
         * 控件高度/2 + 文字高度/2,绘制文字从文字左下角开始,因此"+"
         */
       // float startY = getHeight() / 2 + oRect.height() / 2;
        Paint.FontMetricsInt fm = tPaint.getFontMetricsInt();
        //fm.bottom - fm.top//文字高度
        int startY = getHeight() / 2 - fm.descent + (fm.bottom - fm.top) / 2;
        // 绘制文字
        canvas.drawText(text, startX, startY, tPaint);
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(set_Color);
        mPaint.setStrokeWidth(3);
        bPaint = new Paint();
        bPaint.setStyle(Paint.Style.STROKE);
        bPaint.setAntiAlias(true);
        bPaint.setColor(border_color);
        bPaint.setStrokeWidth(2);
        oRect = new Rect();
        tPaint = new Paint();
        tPaint.setAntiAlias(true);
        tPaint.setStyle(Paint.Style.FILL);
        tPaint.setTextSize(text_Size);
        tPaint.setColor(text_Color);
        tPaint.setAntiAlias(true);
        tPaint.getTextBounds(text, 0, text.length(), oRect);
        tPaint.setStrokeWidth(2);
    }

    /**
     * 调用 getParent().requestDisallowInterceptTouchEvent(true);
     * 方法。一旦底层View收到touch的action后调用这个方法
     * 那么父层View就不会再调用onInterceptTouchEvent了
     *
     * @param ev
     * @return
     */
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (enabler) {
        getParent().requestDisallowInterceptTouchEvent(true);
    }
        return super.dispatchTouchEvent(ev);
    }

    public boolean onTouchEvent(MotionEvent event) {
        if (enabler) {
            // 手指按下:
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    set_Color = clicked_color;//设置按下颜色

                    invalidate();//重新绘制
                    break;

                //手指抬起:
                case MotionEvent.ACTION_UP:
                    if (cListener != null) {
                        if (event.getY() >= mHeight || event.getY() < 0 || event.getX() >= mWith || event.getX() < 0) {
                        } else {
                            cListener.click(cButton.this);
                        }
                    }

                    Log.e(TAG, "onTouchEvent:  ------------" + event.getY());


                    if (enabler) {
                        set_Color = interna_Color;//设置抬起颜色复原
                    } else {
                        set_Color = clicked_color;
                    }

                    invalidate();
                    break;

                // 手指正在移动:
                case MotionEvent.ACTION_MOVE:
                    Log.e(TAG, "onTouchEvent: event.getX()===" + event.getX() + "   mWith========" + mWith);

                    if (event.getY() >= mHeight || event.getY() < 0 || event.getX() >= mWith || event.getX() < 0) {
                        set_Color = interna_Color;

                    } else {
                        set_Color = clicked_color;//设置按下颜色
                    }
                    invalidate();//重新绘制
                    break;
            }
        }
        return true;
    }



    /**
     * 定义接口
     */
    public interface OncButtonListener {

        void click(View v);
    }
    /**
     * 监听回调方法
     */
    public void setcButtonListener(OncButtonListener listener) {

        cListener = listener;
    }

    /**
     * 设置是否可点击
     */
    public void setEnabler(boolean enabler) {

        this.enabler = enabler;
        if (enabler) {
            set_Color = interna_Color;
        } else {//
            set_Color = clicked_color;
        }
        setInvalidate();
    }

    /**
     * 设置文字
     */
    public void setText(String text) {
        this.text = text;

        setInvalidate();
    }

    /**
     * 重绘
     */
    public void setInvalidate() {
        invalidate();
    }
}

layout布局中使用:
声明命名空间:xmlns:cButton=”http://schemas.android.com/apk/res-auto”

<xxf.com.buttontest.cButton
                android:id="@+id/cButton"
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:layout_gravity="center"
                android:layout_marginTop="50dp"
                cButton:enablerd="true"
                cButton:internalcolor="@color/colorPrimary"
                cButton:textcolor="#fff"
                cButton:textsize="20dp"
                cButton:textstr="圆弧边" />

            <xxf.com.buttontest.cButton
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:layout_gravity="center"
                cButton:angletype="anglecir"
                cButton:internalcolor="@color/colorPrimary"
                cButton:textcolor="#fff"
                cButton:textsize="15dp"
                cButton:textstr="圆角" />

结束。

源码http://download.csdn.net/download/xxfen_/9941391

谢谢观看!

猜你喜欢

转载自blog.csdn.net/xxfen_/article/details/77389251