Android自定义View之组合实战(以支付宝页面为例)

前言

自定义View这种东西相信大家也不陌生了,毕竟没吃过猪肉也看过猪跑了吧!
首先看下效果图对比(知道你们找代码主要看效果)

Android自定义View之组合实战(以支付宝页面为例)_第1张图片
支付宝截图
Android自定义View之组合实战(以支付宝页面为例)_第2张图片
自定义控件截图

出来混久了,一是不满足于官方控件反复写,一个是因为人人都是产品经理,需求就多了...
通常,Android实现自定义View有如下三种方式:

  • 将现有控件进行组合,实现功能更加强大控件。
  • 继承现有控件,对其控件的功能进行拓展。
  • 重写View实现全新的控件。

今天就来实践一下简单的自定义View之组合。自定义View这种东西,说难也难,说简单也简单。俗话说得好,纸上得来终觉浅,绝知此事要躬行。看了一下支付宝的界面,觉得有很多地方值得学习,这次就拿一个比较简单的点出来模仿,实现简单自定义View。
效果图已经贴出来了,其实这种效果很常见,几乎每个软件都会有,大同小异而已了。总不能每次都止步于用一个LinearLayout或者RelativeLayout写来写去。

实践

布局
首先按照套路写一个布局,实现我们自定义View需要的效果:



    
    
    
    

这里也没什么特别的,就是普通的布局文件,但是要注意一下边界条件,比如TextView的长度、行数之类的,避免越界。

分析
简单的分析一下,我们要做一个自定义控件,那应该像Android的原生控件一样,能够方便调用者设置控件的属性。比如说这里,我们可以除了常规的设置文字、文字颜色外还能设置左边的icon、右边的icon、左边文字的颜色、右边文字的颜色等。
设置属性也不是很复杂,只需要在res资源目录下的values目录下创建一个attrs.xml属性文件,并在该文件定义你所需要的属性即可。这个自定义控件自定义属性如下:

    
        
        
        
        
        
        
        
        
        
        
        
    

上面的几种属性(format)的意思是:

  1. reference:参考某一资源ID
  2. color:颜色值
  3. boolean:布尔值
  4. dimension:尺寸值
  5. float:浮点值
  6. integer:整型值
  7. string:字符串
  8. fraction:百分数
  9. enum:枚举值
  10. flag:位或运算

目的就是为了告诉系统,这个属性代表了什么。

接下来,我们继承RelativeLayout(为什么是它,因为刚才我们的布局根节点就是RelativeLayout),实现最重要的一步。

/**
 * Created by fdm on 2017/4/2.
 */

public class MenuItem extends RelativeLayout {

    ImageView iconLeft;
    ImageView iconRight;
    TextView menuTextRight;
    TextView menuTextLeft;

    public MenuItem(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

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

    private void init(Context context, AttributeSet attrs) {
        inflate(context, R.layout.menuitem_layout, this);

        iconLeft = getView(R.id.icon_left);
        iconRight = getView(R.id.icon_right);
        menuTextLeft = getView(R.id.menu_text_left);
        menuTextRight = getView(R.id.menu_text_right);

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MenuItemView);
        int rightTextColor = ta.getColor(R.styleable.MenuItemView_rightTextColor, Color.GRAY);
        int leftTextColor = ta.getColor(R.styleable.MenuItemView_leftTextColor, Color.BLACK);
        menuTextRight.setTextColor(rightTextColor);
        menuTextLeft.setTextColor(leftTextColor);

        float textSize = ta.getDimension(R.styleable.MenuItemView_textSize, getResources().getDimension(R.dimen.default_text_size));
        menuTextLeft.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
        menuTextRight.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);

        int leftIconId = ta.getResourceId(R.styleable.MenuItemView_leftIcon, R.mipmap.icon0);
        iconLeft.setImageResource(leftIconId);
        int rightIconId = ta.getResourceId(R.styleable.MenuItemView_rightIcon, R.mipmap.icon_right);
        iconRight.setImageResource(rightIconId);

        String text = ta.getString(R.styleable.MenuItemView_text);
        if (text != null) {
            menuTextLeft.setText(text);
//            menuTextRight.setText(text);
        }
        ta.recycle();

    }

    public void setMenuTextRight(String text) {
        menuTextRight.setText(text);
    }

    public CharSequence getMenuTextRight() {
        return menuTextRight.getText();
    }

    public void setMenuTextLeft(String text) {
        menuTextLeft.setText(text);
    }

    public CharSequence getMenuTextLeft() {
        return menuTextLeft.getText();
    }

    public  T getView(int id) {
        return (T) findViewById(id);
    }
}

首先我们获取到了TypedArray的值:

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

然后就可以获取到具体的属性并设置默认值,最后不要忘记回收TypedArray。这里我们也可以看到,正是R.styleable.MenuItemView将我们自定义的属性一一对应起来。

为了扩展性,我们还可以提供几个方法,这里示例了设置文字内容等。

使用

前面已经准备完毕了,接下来看下怎么使用,就像普通控件那样使用就行了,不过需要带上完整包名。

    

    

    

这里的app是个命名空间(也可以自定义成abc之类的),需要手动引入

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

注意,自定义属性在AS上默认没有智能提示,直接写就对了。这里看到我们可以设置左右两边的icon,文字颜色了。
Activity文件(注:经评论提醒,这里将declare-styleable name="MenuItemView" 跟自定义View的类名MenuItemView统一对应起来就可以智能提示了,疏忽了这个。)

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    MenuItem menuItem;
    MenuItem menuItem1;
    MenuItem menuItem2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        menuItem = getView(R.id.menu);
        menuItem1 = getView(R.id.menu1);
        menuItem2 = getView(R.id.menu2);
        menuItem.setOnClickListener(this);
        menuItem1.setOnClickListener(this);
        menuItem2.setOnClickListener(this);

        menuItem1.setMenuTextRight("0.00元");
        menuItem2.setMenuTextRight("古铜色会员");
    }

    public  T getView(int id) {
        return (T) findViewById(id);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.menu:
                Toast.makeText(this, "蚂蚁花呗", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu1:
                Toast.makeText(this, "余额", Toast.LENGTH_SHORT).show();
                break;
            case R.id.menu2:
                Toast.makeText(this, "蚂蚁会员", Toast.LENGTH_SHORT).show();
                break;
        }
    }
}

运行一下:

Android自定义View之组合实战(以支付宝页面为例)_第3张图片
CustomViewDemo.png

还是有几分神似吧,毕竟我们重要的是实现,不变的是技术,细节随着需求而改变,这里就不深究了吧。

总结

其实按照套路一步步走下来,自定义View的组合大法其实也不是很难,遇到困难就查查资料,相信有付出就有收获。
国际惯例:源码送上https://github.com/brucevanfdm/CustomViewDemo 欢迎star/fork,并提出宝贵意见。

注:程序部分图标来源:阿里巴巴矢量图标库 表示感谢,也顺便打个广告,自来水。

你可能感兴趣的:(Android自定义View之组合实战(以支付宝页面为例))