浅谈自定义View

原创 2015年11月19日 20:49:43

  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的动画效果,这些都是需要我们深入了解的。

源码下载

版权声明:本文为博主原创文章,未经博主允许不得转载。

浅谈Android自定义View

0. 前言本文将对自定义View的原理和方法进行简要讲解,通过此文,你将学到: 安卓的View架构 View的绘图机制 自定义View的方法步骤 1. View控件的架构1.1 View和ViewGr...
  • w19961009
  • w19961009
  • 2016年05月26日 21:17
  • 806

浅谈android自定义view

android 开发也有一段时间了,现在能让自己感觉最大兴奋的还是莫过于自定义view,创造一个从未有过的控件,或者一个炫酷的界面,一定能满足自己的自我成就感。如何去实现从无到有的过程,这是一个艰难的...
  • miss_qz14
  • miss_qz14
  • 2015年12月17日 14:38
  • 325

浅谈自定义view

在工作中会遇到一些安卓系统的控件满足不了业务需求,这样自定义view就可以解决这个问题了。 首选创建个类继承view或者其子类(如果继承imagview就有imageview属性)这样了以v...
  • qq_36237165
  • qq_36237165
  • 2017年03月15日 11:11
  • 94

浅谈Android自定义View

当我们开发中遇到原生的组件无法满足需求时,我们这时候就应该写自定义View来满足一些特殊的组件需求。 自定义View 个人总结自定义View的概念分为两种: 1、在同一个样式的控件组合多处要使用到,我...
  • caihongdao123
  • caihongdao123
  • 2016年06月16日 10:52
  • 7244

Android 中自定义View的初步总结

概述在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了。对于自定义View,可以分为两种,一种是自定义控件(继承View),另...
  • yuminfeng728
  • yuminfeng728
  • 2016年06月08日 13:32
  • 3788

Android自定义view生命周期

定义一个自定义CustomView,在xml中加载,打印MainActivity和view各个生命周期方法,对比如图显示       自定义view的生命周期过程主要分为三个环节,初始准备...
  • ljzdyh
  • ljzdyh
  • 2016年07月26日 15:08
  • 2390

Android自定义View(二、深入解析自定义属性)

转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51454685 本文出自:【openXu的博客】 [TOC] 在上一篇博...
  • u010163442
  • u010163442
  • 2016年05月21日 03:53
  • 17677

自定义View(一)——画线、矩形、圆形、图像

一、最简单的自定义View,什么都不显示,但是有View的特性 com.cctvjiatao.customview.MainActivity package com.cctvjiatao.custom...
  • lvyoujt
  • lvyoujt
  • 2016年03月12日 13:29
  • 4460

自定义View实现手势监听

下面是我自定义的view,主要是实现左右滑动 要实现手势监听,首先要实现OnGestureListener接口 其次是实例化一个GestureDetector:mDetector = new Ge...
  • chengjiamei
  • chengjiamei
  • 2015年06月15日 16:37
  • 1226

自定义view入门

如何自定义控件主要分为以下几个步骤: 1、自定义属性的声明与获取 (1)分析需要的自定义属性 (2)在res/values/attrs.xml定义声明,如 (3)在layout xml文件中进...
  • XSF50717
  • XSF50717
  • 2016年01月16日 21:21
  • 1963
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:浅谈自定义View
举报原因:
原因补充:

(最多只允许输入30个字)