Android自定义控件3:带边框点击背景变色的textview,原型是支付宝手机充值中话费充值按钮

一、原型:支付宝手机充值中话费充值按钮。

二、实现效果:

三、在res/drawable下面创建两个xml:

custom_border_txt_bg.xml用户可点击时,点击切换背景

custom_border_txt_bg2.xml不可以点击时,自定义的背景

custom_border_txt_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@null" android:state_pressed="true">
        <shape android:shape="rectangle">
            <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp" />
            <corners android:radius="5dp" />
            <stroke android:width="1dp" android:color="@color/border_txt_color_default" />
            <solid android:color="@color/border_txt_color_default" />
        </shape>
    </item>
    <item android:drawable="@null">
        <shape android:shape="rectangle">
            <padding android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp" />
            <corners android:radius="5dp" />
            <stroke android:width="1dp" android:color="@color/border_txt_color_default" />
        </shape>
    </item>
</selector>

custom_border_txt_bg2.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <padding
        android:bottom="7dp"
        android:left="7dp"
        android:right="7dp"
        android:top="7dp" />
    <corners android:radius="5dp" />
    <stroke
        android:color="@color/gray"
        android:width="1dp" />
</shape>

四、在res/values/attrs.xml中自定义属性

    <!-- 带边框点击背景变色的textview -->
    <declare-styleable name="borderTxt">
        <attr name="bt_checkable" format="boolean"/><!-- 能否选择 -->
        <attr name="bt_unCheckedColor" format="reference|color"/><!-- bt_checkable=true时,未选中时颜色 -->
        <attr name="bt_checkedColor" format="reference|color"/><!-- bt_checkable=true时,选中时文本颜色 -->
        <attr name="bt_text1" format="string"/><!-- 第一行文本内容 -->
        <attr name="bt_textSize1" format="dimension"/><!-- 第一行字体大小 -->
        <attr name="bt_text2" format="string"/><!-- 第二行文本内容 -->
        <attr name="bt_textSize2" format="dimension"/><!-- 第二行字体大小 -->
    </declare-styleable>

五、自定义控件代码。

package com.custom.controls.button;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.custom.R;
import com.custom.utils.StringUtil;

/**
 * 带边框点击背景变色的textview
 * Created by Kevin on 2016/5/16.
 */
public class BorderTxt extends RelativeLayout implements View.OnTouchListener {
    //不可以点击时,初始颜色
    private int CHECKABLE_FALSE_DEFAULT = getResources().getColor(R.color.gray);
    //可以点击时,初始颜色
    private int CHECKABLE_TRUE_DEFAULT = getResources().getColor(R.color.border_txt_color_default);
    //可以点击时,选中时文本颜色
    private int CHECKABLE_TRUE_TXT = getResources().getColor(R.color.white);

    //是否可以点击
    private boolean checkable;
    /**
     * checkable=false时:unCheckedColor代表不可点击时的初始颜色;
     * checkable=true时:unCheckedColor代表可点击时的初始颜色;checkedColor表示选中时的文字颜色
     */
    private int unCheckedColor,checkedColor;
    private String text1, text2;//文本内容
    private float textSize1, textSize2;//文字大小
    private TextView txt1, txt2;//文本
    private LayoutParams txt1Params, txt2Params, relParams;//位置属性
    private RelativeLayout relativeLayout;//中间两行文本防止在此布局中,便于定位
    private PointF pointF;//存储手指按下的位置
    private Context mContext;//上下文

    public BorderTxt(Context context) {
        super(context);
    }

    public BorderTxt(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public BorderTxt(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        pointF = new PointF();//初始化手指按下时的坐标对象
        //获取自定义属性
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.borderTxt);
        unCheckedColor = array.getColor(R.styleable.borderTxt_bt_unCheckedColor, CHECKABLE_TRUE_DEFAULT);
        checkedColor = array.getColor(R.styleable.borderTxt_bt_checkedColor, CHECKABLE_TRUE_TXT);
        checkable = array.getBoolean(R.styleable.borderTxt_bt_checkable, false);
        text1 = array.getString(R.styleable.borderTxt_bt_text1);
        text2 = array.getString(R.styleable.borderTxt_bt_text2);
        textSize1 = array.getDimensionPixelSize(R.styleable.borderTxt_bt_textSize1, 14);
        textSize2 = array.getDimensionPixelSize(R.styleable.borderTxt_bt_textSize2, 10);
        //自定义属性获取完之后,及时回收
        array.recycle();
        //初始化背景、文字颜色及事件绑定
        initUi();
        //控件位置布局
        relativeLayout = new RelativeLayout(mContext);
        relParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        relParams.addRule(CENTER_IN_PARENT);
        relativeLayout.setLayoutParams(relParams);

        txt1 = new TextView(mContext);
        txt1.setId(StringUtil.generateViewId());
        txt1.setText(text1);
        txt1.setTextColor(unCheckedColor);
        txt1.setTextSize(textSize1);
        //当第二行文本内容为空时,第一行居中显示,否则,将整体居中
        if(StringUtil.isEmpty(text2)){
            txt1Params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            txt1Params.addRule(RelativeLayout.CENTER_IN_PARENT);
        }else{
            txt1Params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            txt1Params.addRule(RelativeLayout.CENTER_HORIZONTAL);
            txt1.setGravity(Gravity.CENTER);

            txt2 = new TextView(mContext);
            txt2.setText(text2);
            txt2.setTextSize(textSize2);
            txt2.setTextColor(unCheckedColor);

            txt2Params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            txt2Params.addRule(RelativeLayout.CENTER_HORIZONTAL);
            txt2Params.addRule(BELOW, txt1.getId());
            relativeLayout.addView(txt2, txt2Params);
        }
        //初始化文本颜色
        setTxtColor(unCheckedColor);
        relativeLayout.addView(txt1, txt1Params);
        addView(relativeLayout);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        /**
         * 可以点击时,手指第一次按下时存储此时的位置坐标;
         * 当手指抬起或者移动与按下时的坐标任意方向上的长度大于三分之一控件长度时,
         * 控件的press效果失效,并改变文本颜色。
         */
        if(checkable){
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                pointF.x = event.getX();
                pointF.y = event.getY();
                //按下
                setTxtColor(checkedColor);
            } else if (event.getAction() ==  MotionEvent.ACTION_UP
                    || getWidth() / 3 - Math.abs(event.getX() - pointF.x) < 0
                    || getHeight() / 3 - Math.abs(event.getY() - pointF.y) < 0
                    ) {
                //抬起
                this.setPressed(false);
                setTxtColor(unCheckedColor);
            }
        }
        return false;
    }

    /**
     * 设置文本颜色
     * @param color
     */
    public void setTxtColor(int color){
        txt1.setTextColor(color);
        if(!StringUtil.isEmpty(text2)){
            txt2.setTextColor(color);
        }
    }

    /**
     * 得到是否可以点击
     * @return
     */
    public boolean isCheckable() {
        return checkable;
    }

    /**
     * 设置是否可以点击
     * 并刷新控件状态
     * @param checkable
     */
    public void setCheckable(boolean checkable) {
        this.checkable = checkable;
        refreshDrawableState();//执行改变逻辑
        setTxtColor(unCheckedColor);//初始化文字颜色
    }

    /**
     * 执行控件改变
     */
    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        //改变时的切换逻辑
        initUi();
    }

    /**
     * 初始化背景、文字颜色及事件绑定
     */
    private void initUi() {
        if(checkable){
            unCheckedColor = CHECKABLE_TRUE_DEFAULT;
            checkedColor = CHECKABLE_TRUE_TXT;
            setBackgroundResource(R.drawable.custom_border_txt_bg);
            setOnTouchListener(this);
            /**
             * 绑定点击事件监听,否则点击时无法切换背景,selector效果无效;
             * 我的理解就是让空间拥有获得焦点的能力,尽管什么都没做
             */
            this.setOnClickListener(null);
        }else{
            unCheckedColor = CHECKABLE_FALSE_DEFAULT;
            setBackgroundResource(R.drawable.custom_border_txt_bg2);
        }
    }
}

六、res\layout中定义布局文件:activity_border_txt.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:borderTxt="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.custom.controls.button.BorderTxt
        android:id="@+id/btt"
        android:layout_width="200dp"
        android:layout_height="120dp"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        borderTxt:bt_text1="第一行"
        borderTxt:bt_text2="第二行" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp"
        android:orientation="horizontal">

        <com.custom.controls.button.BorderTxt
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_weight="1"
            borderTxt:bt_text1="10元"
            borderTxt:bt_text2="售价10.00元" />

        <com.custom.controls.button.BorderTxt
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_weight="1"
            borderTxt:bt_checkable="true"
            borderTxt:bt_text1="20元"
            borderTxt:bt_text2="售价20.00元" />

        <com.custom.controls.button.BorderTxt
            android:id="@+id/border_txt_flow"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:layout_marginLeft="5dp"
            android:layout_marginRight="5dp"
            android:layout_weight="1"
            borderTxt:bt_text1="30M" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_change_border_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="改变按钮可选与否"></Button>
</LinearLayout>

七、注意

1、颜色是在colors.xml中自定义的,

R.color.gray  #C0C0C0
R.color.border_txt_color_default #3399FF
R.color.white #FFFFFF

2、this.setOnClickListener(null);一定要写,绑定点击事件监听,否则点击时无法切换背景,selector效果无效;

我的理解就是让空间拥有获得焦点的能力,尽管什么都没做。

3、注意setCheckable()和drawableStateChanged()中的逻辑位置,此例中

setCheckable()中的setTxtColor(unCheckedColor)如果放到drawableStateChanged()中的话,会因为drawableStateChanged()的重复调用而导致预期结果异常。

4、使用时,一定要加上命名空间

xmlns:borderTxt="http://schemas.android.com/apk/res-auto"

以下问题可以直接点击了解:

declare-styleable:自定义控件的属性

自定义控件中setText()设置字体相同大小无法与原生控件一致

时间: 2024-10-10 08:40:09

Android自定义控件3:带边框点击背景变色的textview,原型是支付宝手机充值中话费充值按钮的相关文章

android自定义控件实现TextView按下后字体颜色改变

今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能 直接看图片             第一张是按下后截的图,功能很简单,也很容易实现,下面来看一下如何通过重写TextView来实现 一共三个文件  TextViewM.java,MainActivity.java,activity_textview.xml TextViewM.java 1 package landptf.control; 2 3 import and

c#自定义控件窗体Click无法点击Lable的处理解决方案

自定义控件做按钮,不继承Button,用Lable来做按钮文字时,点击空白处有效,但是点击lable不起作用的处理方案. 很简单,就是在Lable添加Click事件,事件中添加代码:OnClick(e);完整代码如下: private void label1_Click(object sender, EventArgs e) { OnClick(e); } 这样的话,就能在窗体中使用自定义控件的CLick事件时点击Lable也生效了,依次类推,如果你的按钮含有图片(Picbox)之类的,也在他的

Android自定义控件背景及其Drawable以实现扁平化

扁平化? 人们都说扁平化是从IOS和WindowsPhone那边吹过来的邪风,但是不可否认:扁平化是我见过的最舒服.最自然的表现方式.从开发角度上来讲,扁平化的设计可以使得我们从许多屏幕适配和尺寸调节的工作中解放出来(虽然只是那么一点点),更加关注功能:而在在使用层面上,只要文化水平不是特别地低(没有恶意),拟物化的那点提示作用也不是那么明显,当然这里不是说拟物化不好,总之:相对于其他表现方式,扁平化碉堡了. 咱们也做一个扁平化 上面说了,扁平化的控件其实在开发中是非常容易的.这里让我们一起动手

android 圆角边框、渐变背景的TextView

加一个红色的边框: textView的XML: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_

【Android UI】案例02 圆角边框、圆角背景的实现(shape)

本文主要分享圆角边框与圆角背景的实现方式.该方式的实现,需要了解shape的使用,该部分的详细介绍,请阅读博客http://blog.csdn.net/mahoking/article/details/23672271.文中有较详细的介绍. [转载使用,请注明出处:http://blog.csdn.net/mahoking] 如下是演示的shape_layout.xml模板. <?xml version="1.0" encoding="utf-8"?>

【Android】编写Drawable XML绘制底部带指示条的背景

要实现的就是类似于Actionbar标签的那种效果,底部有一条指示条. 实现代码: <?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item android:top="-6dp" android:left="-6d

android 带边框的圆角按钮

新建buttonstyle.xml 代码如下 <?xml version="1.0" encoding="UTF-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 连框颜色值 --><item> <shape> <solid android:color="#1

Android自定义带边框的圆形view

由于项目需要,需要做一个圆形的带边框并且里边还有文字的view →_→ ↓↓↓↓这样↓↓↓↓ 如果在布局文件中做的话是非常麻烦的,而且复用性也不高.所以想到用自定义一个view的来实现该功能,这样封装性和复用性就会相对提高,可方便在以后类似的项目中使用.可能也有同学有过这样的需求,所以在这分享出来供大家参考,不足之处还请多多指点. 看代码: 1package com.stock.manage.friend.view;import android.content.Context; 2 import

设置View只显示透明下边框、透明背景框、阴影背景框的方法

实现的效果如下: 下面的代码是实现一个带边框的xml,很常见 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@android:color/transparent" /> <str