浅谈自定义View

  Android提供了比较丰富的组件库来创建UI,但是并不能完全满足我们的需求,考虑到这一点Google给我们提供非常方便的拓展方法,我们可以在原有控件的基础上来自定义满足我们需求的View。掌握自定义View,是Android开发的一项重要内容。那么如何实现自定义view呢,方法有很多。我要说的是比较简单的创建复合控件。
  一般有以下几步:
  1.继承一个合适的ViewGroup
  2.定义属性
  3.组合组件
  4.定义接口并开发给调用者

  继承一个合适的ViewGroup
  第一步很简单,根据自己的需要继承合适的ViewGroup就可以了,例如LinearLayout,FrameLayout。这样做的好处是在系统提供的组件的基础上实现我们想要的效果,不必考虑一些其他的问题。
  
  定义属性
  这在Android中也非常的简单,只需要在res资源目录的values目录下创建attrs.xml文件,在该文件中做相应的定义即可:
  

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="add_and_sub">
        <!--最小数量-->
        <attr name="minCount" format="integer"/>
    </declare-styleable>
</resources>

其中

<declare-styleable name="add_and_sub"></declare-styleable>

标签申明使用自定义的属性,并且设置引用name为add_and_sub 然后在通过<attr>申明具体的属性。这里申明的是最小数量minCount,并且设置integer类型。当然这里的format可以使用多种类型,各属性之间用“|”隔开。

  组合组件
  我们定义类 AddAndSubButton 继承自FrameLayout,在构造方法中使用TypedArray来获取我们定义的属性:
  

TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);

使用TypedArray提供的getXXX()方法获取相应的属性。如:

 ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);
        //设置默认最小值为1    CurrentCount=minCount=ta.getInt(R.styleable.add_and_sub_minCount,1);

获取完后不要忘记调用recycle()

接下来我们就需要组合我们的控件了:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="35dp"
    android:orientation="horizontal" >

    <Button
        android:id="@+id/btn_sub"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:padding="10dp"
        android:background="@drawable/bg_sub_btn"
        android:clickable="false"
        android:focusable="false"
         />

    <EditText
        android:id="@+id/edit_count"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center"
        android:minWidth="70dp"
        android:text="1"
        android:inputType="number"
        android:maxLength="7"
        android:background="@drawable/bg_count_shape"
        android:textColor="#595959"
        android:textSize="18sp" />

    <Button
        android:id="@+id/btn_add"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:padding="10dp"
        android:background="@drawable/bg_add_btn"
         />

</LinearLayout>

很简单,就是使用了两个button和一个EditText。然后在AddAndSubButton类中做具体的实现了。

import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;

import com.chuck.mobile.changecountview.R;

/**
 * 自定义可以修改数量的button
 */
public class AddAndSubButton extends FrameLayout {
    /**自定义属性集合*/
    private TypedArray ta;
    /**减按钮*/
    private Button btn_sub;
    /**加按钮*/
    private Button btn_add;
    /**数量显示*/
    private EditText edit_count;
    /**最小数量*/
    private int minCount;
    /**目前数量*/
    private int CurrentCount;
    public AddAndSubButton(Context context,AttributeSet attrs) {
        super(context, attrs);
        ta=context.obtainStyledAttributes(attrs, R.styleable.add_and_sub);
        LayoutInflater.from(context).inflate(R.layout.widget_add_and_sub,this);
        btn_add= (Button) findViewById(R.id.btn_add);
        btn_sub= (Button) findViewById(R.id.btn_sub);
        edit_count= (EditText) findViewById(R.id.edit_count);
        //设置默认最小值为1
        CurrentCount=minCount=ta.getInt(R.styleable.add_and_sub_minCount,1);
        ta.recycle();
        edit_count.setText(minCount+"");
        edit_count.setEnabled(false);
        setSubBtnEnable(false);

        btn_sub.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                updateSubButtonStatus();
            }
        });
        btn_add.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                updateAddButtonStatus();
            }
        });

    }

    private void updateAddButtonStatus() {
        if(CurrentCount>=minCount){
            setSubBtnEnable(true);
            btn_sub.setBackgroundDrawable(getResources().getDrawable(
                    R.drawable.bg_sub_btn));
        }
        setTextCount(CurrentCount+1);
    }

    private void updateSubButtonStatus() {
        if (CurrentCount > minCount) {
            setTextCount(CurrentCount - 1);
            if (CurrentCount == minCount) {
                btn_sub.setBackgroundDrawable(getResources().getDrawable(
                        R.mipmap.ic_sub_btn_error));
            }
        } else {
            setSubBtnEnable(false);
            btn_sub.setBackgroundDrawable(getResources().getDrawable(
                    R.mipmap.ic_sub_btn_error));
        }
    }

    /**
     * 设置数量
     *
     * @param count
     */
    public void setTextCount(int count) {
        CurrentCount=count;
        edit_count.setText(CurrentCount + "");

    }

    /**
     * 设置数量
     *
     * @param count
     */
    public void setTextColor(int color) {
        edit_count.setTextColor(color);
    }

    /**
     * 设置是否可编辑
     *
     * @param editable
     */
    public void setEditable(boolean editable) {
        edit_count.setEnabled(editable);
    }

    public void setMinCount(int minCount){
        this.minCount = minCount;
    }

    /**
     * 获取当前的数量 (默认返回-1 为无效值 )
     *
     * @return
     */
    public int getCount() {
        int count = -1;// 默认返回-1 无效值
        String text = edit_count.getText().toString().trim();
        if (!TextUtils.isEmpty(text)) {
            try {
                count = Integer.parseInt(text);
            } catch (NumberFormatException e) {
                e.printStackTrace();
            }
        }
        return count;
    }

    /**
     * 设置减按钮是否可点击 false不可再点击 true可以点击
     *
     * @param flag
     */
    public void setSubBtnEnable(boolean flag) {
        btn_sub.setFocusable(flag);
        btn_sub.setClickable(flag);
        if (flag) {
            btn_sub.setBackgroundDrawable(getResources().getDrawable(
                    R.drawable.bg_sub_btn));
        } else {// 设置减按钮不可继续点击
            btn_sub.setBackgroundDrawable(getResources().getDrawable(
                    R.mipmap.ic_sub_btn_error));
        }
    }

    /**
     * 设置加按钮是否可点击 false不可再点击 true可以点击
     *
     * @param flag
     */
    public void setAddBtnEnable(boolean flag) {
        btn_add.setFocusable(flag);
        btn_add.setClickable(flag);
        if (flag) {
            btn_add.setBackgroundDrawable(getResources().getDrawable(
                    R.drawable.bg_add_btn));
        } else {// 设置加按钮不可继续点击
            btn_add.setBackgroundDrawable(getResources().getDrawable(
                    R.mipmap.ic_add_btn_error));
        }
    }

    public Button getAddButton() {
        return btn_add;
    }

    public Button getSubButton() {
        return btn_sub;
    }
}

实现了类似淘宝购物车修改宝贝数量的button。点击左边button数量减1,点击右边button数量加1。这里也可以根据需求的不同提供相应的接口。

   定义接口并开发给调用者
   在AddAndSubButton类中定义接口,如:
   

 public interface AddbuttonLongClickListener{
        public void onLongClick(View view);
    }

开发给调用者:

 public void setOnAddButtonLongClickListener(AddbuttonLongClickListener listener){
        this.listener=listener;
    }

  这里根据自己的需求,在自定义View中添加相应的接口。也可以将成员方法设置为public 供调用者使用。
  然后我们的View可以使用了
  

<com.chuck.mobile.changecountview.widget.AddAndSubButton
        android:id="@+id/aasb_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:minCount="2">

运行结果
这里写图片描述

总结:自定义View有很多方法,感兴趣的可以去了解一下。这里只是较浅的介绍了其中一种方法。并且自定义View还需要注意很多问题,如滑动冲突的解决,让View支持wrap_content,和View的动画效果,这些都是需要我们深入了解的。

源码下载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值