android组件不能加适配器,关于android中为一些ViewGroup加上适配器的一些看法

先不说别的, 上图:

41e395cd8f3c

S60520-123210.jpg

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

颜色,品牌,尺寸,等规格,每个规格里面有长短不一,大小不一,数量不一的规格项,如果用GridView,则每一项的个数, 都会固定,实现不了这种错落排版的效果。

怎么办?

怎么办?

怎么办?

于是在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的改造已经完工了,

回到第一张图上去,看看怎么用的吧

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">

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"

/>

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"/>

public class SelectGuigeAdapter extends LBaseAdapter {

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 {

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是什么鬼, 大家可以关注下我的上一遍文章

关于android中ListView的Adapter如何设计能通用的一些看法

嗯,先到这,写的不好,望指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值