关于android中为一些ViewGroup加上适配器的一些看法

先不说别的, 上图:

S60520-123210.jpg

项目中,我们可能会遇到以上那种情况 ,

颜色,品牌,尺寸,等规格,每个规格里面有长短不一,大小不一,数量不一的规格项,如果用GridView,则每一项的个数, 都会固定,实现不了这种错落排版的效果。
<strong>怎么办?</strong>
<strong>怎么办?</strong>
<strong>怎么办?</strong>
于是在github上逛了一圈, 找到了我想要的:
https://github.com/blazsolar/FlowLayout
感谢前人们为我们提供的方便


到这里,还没有结束, 下面才是今天要讨论的东西。
这个FlowLayout,一般用法是addView(view),可是,我还要嵌套在一个listview里面,要在getView里面每次

for(xx : xx) {
 View view = View.inflate(xxxx,xxx,xx);
 Xx xx = view.findViewById(R.id.xx)
 Xx xx = ....;
 xx.setText(xx);
 ...
}

好可怕 。
怎么办?
android已经给我们提供指导方向了, 所以我们在使用ListView,GridView等等多条目控件的时候,会写一个适配器,把数据层给分开,那这个能加一个适配器吗,ok,老思路先分析 :

1.首先我要给FlowLayout加个setAdapter(ListAdapter adapter);
2.数据变动我要改动Flowlayout里面的view,看看ListView源码,要给adapter注册一个Observer,类似这样:
adapter.registerDataSetObserver(new DataSetObserver() {

            @Override
            public void onChanged() {
                changeViews();
            }

            @Override
            public void onInvalidated() {
                changeViews();
            }
        });
实现这个之后,在adapter的notifyDatasetChange的时候,onChanged方法就会回调
3.利用adapter的getView来得到赋值好的view,并加到FlowLayout,
4.能不能考虑下复用view,不能每次removeAllViews()再addView啊。

好了,分析完了,从第一条开始上代码:

    private ListAdapter adapter;
    public void setAdapter(@NonNull ListAdapter adapter) {
        if (adapter == null) throw new NullPointerException("FlowLayout.setAdapter不能传空参数");
        this.adapter = adapter;
        changeViews(); //这个是用来给Flowlayout加view的逻辑,先忽略
        adapter.registerDataSetObserver(new DataSetObserver() {

            @Override
            public void onChanged() {
                changeViews();
            }

            @Override
            public void onInvalidated() {
                changeViews();
            }
        });
    }

代码很简单,
1.就是在FlowLayout里面保留一个adapter,
2.然后从adapter里面询问view,
3.注册观察对象,得以在adapter.notifyDataSetChanged()的时候,能感知到。

本身很简单,一共就两个方法嘛~
下面贴changeViews()方法:

private void changeViews() {
        final int count = adapter.getCount();
        if (count > 0) {
            int childCount = getChildCount();
            if (childCount > count) {
                removeViews(count, childCount - count);
            }
            for (int i = 0; i < count; i++) {
                final View view = adapter.getView(i, getChildAt(i), this);
                if (view.getLayoutParams() == null) {
                    LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                    lp.rightMargin  = childHorizontal;
                    lp.bottomMargin = childVerticle;
                    view.setLayoutParams(lp);
                }
                if(getChildAt(i) != view) {
                    addView(view);
                }
            }
        }else{
            removeAllViews();
        }
    }

这里稍微麻烦点,
为什么呢?因为考虑到我们不能每一次都让adapter重新创建新view,这样实则是一种性能上的浪费,但是真做到ListView那种级别的复用,也是难。所以,我就简单点做,能复用就复用,不能复用再创建。

"能复用就复用,不能复用再创建" 怎么体现出来的呢?

final int count = adapter.getCount();  //先拿到要显示的view的数量
        if (count > 0) {    
            //在即将显示的数量大于0的情况下 再lookup一下flowlayout当前子view的数量
            int childCount = getChildCount();   
            if (childCount > count) { 
                //如果说flowlayout当前的子view数量多过要显示的view数量,那就删除几个,让其数量保持一致
                removeViews(count, childCount - count);
            }
//上面就是我所说的‘能复用就复用,不能复用再创建‘

for (int i = 0; i < count; i++) {
//这个就比较简单了, 向adapter要view。
//getChildAt(i) 就是adapter内getView中的第二个参数 convertView,
//如果有就传过去 ,没有就是null,这时按正常来说,我们会重新创建一个view。
                final View view = adapter.getView(i, getChildAt(i), this);
                if (view.getLayoutParams() == null) {
//好了,这时呢得到了一个view,看看有没有 布局参数,
//没有就给一个,免得FlowLayout自动生成一个的话
//会match_parent,这样就不合我们的要求了,
                    LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
//这些就是加加右和下margin,让view 不会粘一起,好看一点,
//可以做成一个自定义属性嘛,从xml里面读,这个就不讨论了,
                    lp.rightMargin  = childHorizontal;
                    lp.bottomMargin = childVerticle;
                    view.setLayoutParams(lp);
                }
  
                if(getChildAt(i) != view) {
//这里,为啥要判断下呢?
//这要说到前面的蹩脚的复用了,
//前面把getChildAt(i)传给了getView,如果FlowLayout本身就有view,
//那么在getView里面,就只是改变一下text,image等等的数据,这时
//getChildAt(i) 和adater返回的view肯定还是同一个view,所以不用重复加
//----
//但是如果不一样,那就是说,getChildAt(i)就是null , 跟本就没有,
                    addView(view);
                }
            }

ok,FlowLayout的改造已经完工了,
回到第一张图上去,看看怎么用的吧

<?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_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:padding="@dimen/dp10"
    android:background="#fff"
    android:orientation="vertical">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="42dp"
        android:gravity="center_vertical"
        android:textColor="@color/normalText"
        android:textSize="@dimen/normal"
        />
    <demo.FlowLayout
        android:id="@+id/flowLayout"
        android:layout_marginTop="@dimen/dp10"
        app:childHorizontal="5dp"
        app:childVerticle="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>
public class SelectGuigeAdapter extends LBaseAdapter<GuigeBean, SelectGuigeAdapter.VH> {

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

    @Override
    public VH createViewHolder(ViewGroup parent, int position) {
        return new VH(View.inflate(getContext(),R.layout.select_guige_list_item,null));
    }


    @Override
    public void bindViewHolder(VH holder, GuigeBean data, int position) {
        holder.txtTitle.setText(data.name);  //这里显示的是颜色,品牌等
        holder.mAdapter.setDataSource(data.items, true); //这里是具体的规格项
    }

    static class VH extends LBaseAdapter.ViewHolder {

        private TextView txtTitle;
        private FlowLayout flowLayout;
        private SelectGuigeItemAdapter mAdapter;

        public VH(View convertView) {
            super(convertView);
            txtTitle = get(R.id.title);
            flowLayout = get(R.id.flowLayout);
            if (mAdapter == null) {
                mAdapter = new SelectGuigeItemAdapter(getContext());
                flowLayout.setAdapter(mAdapter);
            }
        }
    }

}

再看FlowLayout的适配器

public class SelectGuigeItemAdapter extends LBaseAdapter<String, LBaseAdapter.ViewHolder> {

    public SparseBooleanArray selectMap = new SparseBooleanArray();

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

    @Override
    public ViewHolder createViewHolder(ViewGroup parent, int position) {
        return new ViewHolder(View.inflate(getContext(), R.layout.checkedtextview_item,null));
    }

    @Override
    public void bindViewHolder(ViewHolder holder, String data, final int position) {
        CheckedTextView txt = holder.get(R.id.text);
        txt.setText(data);
        txt.setChecked(selectMap.get(position,false));
        txt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                selectMap.clear();
                selectMap.put(position, true);
                notifyDataSetChanged();
            }
        });
    }
}

ok,连起来了, 这个LBaseAdapter是什么鬼, 大家可以关注下我的上一遍文章
<a href="http://www.jianshu.com/p/7b7dbbebfb4f">关于android中ListView的Adapter如何设计能通用的一些看法</a>
嗯,先到这,写的不好,望指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容