Android标签容器控件的实现

本文介绍了如何在Android中实现一个自定义的标签容器控件,通过重写`onMeasure`和`onLayout`方法来实现自适应屏幕宽度的布局。文章详细讲解了原理,包括自定义ViewGroup时要考虑的Child控件margin属性,以及模仿ListView的Adapter模式操作控件内容。此外,还提供了实现过程的步骤和相关代码示例。
摘要由CSDN通过智能技术生成

Android中标签容器控件的实现

介绍

在一些APP中我们可以看到一些存放标签的容器控件,和我们平时使用的一些布局方式有些不同,它们一般都可以自动适应屏幕的宽度进行布局,根据对自定义控件的一些理解,今天写一个简单的标签容器控件,项目源码在最后给出

下面这个是我在手机上截取的一个实例,是在MIUI8系统上截取的

这里写图片描述

这个是我实现的效果图

这里写图片描述

原理介绍

根据对整个控件的效果分析,大致可以将控件分别从以下这几个角度进行分析:

1.首先涉及到自定义的ViewGroup,因为现有的控件没法满足我们的布局效果,就涉及到要重写onMeasure和onLayout,这里需要注意的问题是自定义View的时候,我们需要考虑到View的Padding属性,而在自定义ViewGroup中我们需要在onLayout中考虑Child控件的margin属性否则子类设置这个属性将会失效。整个View的绘制流程是这样的:

最顶层的ViewRoot执行performTraversals然后分别开始对各个View进行层级的测量、布局、绘制,整个流程是一层一层进行的,也就是说父视图测量时会调用子视图的测量方法,子视图调孙视图方法,一直测量到叶子节点,performTraversals这个函数翻译过来很直白,执行遍历,就说明了这种层级关系。

2.该控件形式上和ListView的形式比较相近,所以在这里我也模仿ListView的Adapter模式实现了对控件内容的操作,这里对ListView的setAdapter和Adapter的notifyDataSetChanged方法做个简单的解释:

在ListView调用setAdapter后,ListView会去注册一个Observer对象到这个adapter上,然后当我们在改变设置到adapter上的数据发改变时,我们会调用adapter的notifyDataSetChanged方法,这个方法就会通知所有监听了该Adapter数据改变时的Observer对象,这就是典型的监听者模式,这时由于ListView中的内部成员对象监听了该事件,就可以知道数据源发生了改变,我们需要对真个控件重新进行绘制了,下面来一些相关的源码。

Adapter的notifyDataSetChanged

public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

ListView的setAdapter方法

@Override
    public void setAdapter(ListAdapter adapter) {
        /**
         *每次设置新的适配的时候,如果现在有的话会做一个解除监听的操作
         */
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }

        resetList();
        mRecycler.clear();
        /** 省略部分代码.....   */
        if (mAdapter != null) {
            mAreAllItemsSelectable = mAdapter.areAllItemsEnabled();
            mOldItemCount = mItemCount;
            mItemCount = mAdapter.getCount();
            checkFocus();

            /**
            *在这里对adapter设置了监听,
            *使用的是AdapterDataSetObserver类的对象,该对象定义在ListView的父类AdapterView中
            */
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
            /** 省略 */
        } else {
            /** 省略 */
        }

        requestLayout();
    }

AdapterView中的内部类AdapterDataSetObserver

class AdapterDataSetObserver extends DataSetObserver {
   

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            /* ***代码略*** */
            checkFocus();
            requestLayout();
        }

        @Override
        public void onInvalidated() {
           /* ***代码略*** */
            checkFocus();
            requestLayout();
        }

        public void clearSavedState() {
            mInstanceState = null;
        }
    }

一段伪代码表示

ListView{
    Observer observer{
         onChange(){
              change;
         }
    }

    setAdapter(Adapter adapter){
         adapter.register(observer);
    }
}

Adapter{
    List<Observer> mObservable;
    register(observer){
        mObservable.add(observer);
    }
    notifyDataSetChanged(){
        for(i-->mObserverable.size()){
            mObserverable.get(i)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值