alibaba / vlayout

Project vlayout is a powerfull LayoutManager extension for RecyclerView, it provides a group of layouts for RecyclerView. Make it able to handle a complicate situation when grid, list and other layouts in the same recyclerview.
http://tangram.pingguohe.net/
MIT License
10.79k stars 1.79k forks source link

关于VLayout不支持横向线性布局的个人解决方案,有需要的进来看看 #449

Open XXQAQ opened 5 years ago

XXQAQ commented 5 years ago

我觉得横向线性布局在开发中还是一个很常见的需求,VLayout官方不提供这个功能导致要做很多处理,如果处理地不好的话好会导致这部分Adapter不能复用,这对于我这种代码洁癖的人来说还是很苦恼的。 经过再三考虑,我使用了装饰者模式封装了一个横向布局Adapter,外界只需要传入真实的Adapter即可实现横向布局,以下为代码 ` public class VLayoutHorizontalAdapter extends DelegateAdapter.Adapter{

private RecyclerView.Adapter adapter;
private int spanCount = 1;  //横向的列,填1相当于横向线性布局,根据自己的需求更改这个值
private RecyclerView.ItemDecoration decoration;

public VLayoutHorizontalAdapter(RecyclerView.Adapter adapter) {
    this.adapter = adapter;
}

public VLayoutHorizontalAdapter(RecyclerView.Adapter adapter, int spanCount) {
    this.adapter = adapter;
    this.spanCount = spanCount;
}

public VLayoutHorizontalAdapter(RecyclerView.Adapter adapter, int spanCount, RecyclerView.ItemDecoration decoration) {
    this.adapter = adapter;
    this.spanCount = spanCount;
    this.decoration = decoration;
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
    RecyclerView rv = new RecyclerView(viewGroup.getContext());
    rv.setLayoutManager(new GridLayoutManager(viewGroup.getContext(),spanCount,RecyclerView.HORIZONTAL,false));
    if (decoration != null) rv.addItemDecoration(decoration);
    rv.setAdapter(adapter);
    return new BaseViewHolder(rv,viewType);
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    adapter.notifyDataSetChanged();
}

@Override
public int getItemCount() {
    return 1;
}

@Override
public LayoutHelper onCreateLayoutHelper() {
    return new LinearLayoutHelper();
}

} `

使用时只需要如下调用 delegateAdapter.addAdapter(new VLayoutHorizontalAdapter(new ReallyAdapter()));

PS:外界不需要持有ReallyAdapter引用,因为VLayoutHorizontalAdapter已经做了处理,更新VLayoutHorizontalAdapter即可更新ReallyAdapter。还有一点就是DelegateAdapter.Adapter继承于RecyclerView.Adapter,具体好处自己体会

MrZzhouWorld commented 5 years ago

难道不会卡顿么,这样添加横向布局

XXQAQ commented 5 years ago

难道不会卡顿么,这样添加横向布局

官方Demo中就是这样添加的,只是官方是直接嵌套使用,这样会导致Adapter的复用性太差,我才做了一层封装。日后如果官方出了横向Adapter,可以直接修改继承的父类,切换起来也方便

oksimple commented 5 years ago

你这里面的BaseViewHolder那里来的?

XXQAQ commented 5 years ago

你这里面的BaseViewHolder那里来的?

你自己BaseViewHolder 或者 直接使用RecyclerView.ViewHolder

oksimple commented 5 years ago

大佬 我折腾一下午了,用你这个 recyclerview 死活不显示 会是什么情况呢? 换成什么textview 之类的就没问题

XXQAQ commented 5 years ago

大佬 我折腾一下午了,用你这个 recyclerview 死活不显示 会是什么情况呢? 换成什么textview 之类的就没问题

你有没有通知VLayoutHorizontalAdapter 更新?

oksimple commented 5 years ago

只要能 notifyDataSetChanged 的地方 我都调用了

XXQAQ commented 5 years ago

只要能 notifyDataSetChanged 的地方 我都调用了

贴一下代码,看看你是通知的哪个Adapter更新

oksimple commented 5 years ago
 //横向的adapter
                            HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list);
                            //
                            VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter);

                            adapter.addAdapter(vLayoutHorizontalAdapter);
                        }

                        //这个adapter是DelegateAdapter
                        adapter.notifyDataSetChanged();
oksimple commented 5 years ago

我的 VLayoutHorizontalAdapter 是再for循环中动态new的应为有N组不固定的数据

XXQAQ commented 5 years ago

//横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter);

                        adapter.addAdapter(vLayoutHorizontalAdapter);
                    }

                    //这个adapter是DelegateAdapter
                    adapter.notifyDataSetChanged();

`//横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter); adapter.addAdapter(vLayoutHorizontalAdapter); }

                //更新的时候不可以使用DelegateAdapter,要使用具体的子Adapter
                vLayoutHorizontalAdapter .notifyDataSetChanged();`
oksimple commented 5 years ago

for (int x = 0; x < 20; i++) { for (int j = 0; j < 10; j++) { list.add("xxxxx"); } //横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter); adapter.addAdapter(vLayoutHorizontalAdapter); } //这个adapter是DelegateAdapter adapter.notifyDataSetChanged();

oksimple commented 5 years ago

更新 子 adapter 也无效,但是把recyclerview 换成其他控件 就没问题

XXQAQ commented 5 years ago

//横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter); adapter.addAdapter(vLayoutHorizontalAdapter); }

                //这个adapter是DelegateAdapter
                adapter.notifyDataSetChanged();

            //更新的时候不可以使用DelegateAdapter,要使用具体的子Adapter
            vLayoutHorizontalAdapter .notifyDataSetChanged();`

//横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter); adapter.addAdapter(vLayoutHorizontalAdapter); }

                //这个adapter是DelegateAdapter
                adapter.notifyDataSetChanged();

//横向的adapter HomeHorizontalAdapter homeHorizontalAdapter = new HomeHorizontalAdapter(list); // VLayoutHorizontalAdapter vLayoutHorizontalAdapter = new VLayoutHorizontalAdapter(homeHorizontalAdapter); adapter.addAdapter(vLayoutHorizontalAdapter); } //更新的时候不可以使用DelegateAdapter,要使用具体的子Adapter vLayoutHorizontalAdapter .notifyDataSetChanged();

``

更新 子 adapter 也无效,但是把recyclerview 换成其他控件 就没问题

最外层的RecyclerView是不是MatchParent

oksimple commented 5 years ago

是 match_parent

XXQAQ commented 5 years ago

你先试试 不用VLayoutHorizontalAdapter ,先用VLayout自带的GridLayoutHelper,看看能不能显示

oksimple commented 5 years ago

我再添加横向recyclerview 之前还添加了其他 layouthelp SingleLayoutHelper 都能正常显示 但是到了 添加 横向的这里 就显示不了 GridLayoutHelper我用过 没问题。

oksimple commented 5 years ago

把 onCreateViewHolder 中的 recyclerview 替换成 其他控件 也没问题。

XXQAQ commented 5 years ago

public class VLayoutHorizontalAdapter extends DelegateAdapter.Adapter {

private RecyclerView.Adapter adapter;
private RecyclerView.ItemDecoration decoration;

public VLayoutHorizontalAdapter(RecyclerView.Adapter adapter) {
    this.adapter = adapter;
}

public VLayoutHorizontalAdapter(RecyclerView.Adapter adapter,RecyclerView.ItemDecoration decoration) {
    this.adapter = adapter;
    this.decoration = decoration;
}

@Override
public LayoutHelper onCreateLayoutHelper() {
    return new LinearLayoutHelper();
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    RecyclerView rv = new RecyclerView(parent.getContext());
    rv.setLayoutManager(new GridLayoutManager(parent.getContext(),1,RecyclerView.HORIZONTAL,false));
    if (decoration != null) rv.addItemDecoration(decoration);
    rv.setAdapter(adapter);
    return new RecyclerView.ViewHolder(rv){};
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    adapter.notifyDataSetChanged();
}

@Override
public int getItemCount() {
    return 1;
}

}

XXQAQ commented 5 years ago

把 onCreateViewHolder 中的 recyclerview 替换成 其他控件 也没问题。

看看试试我楼上的评论

XXQAQ commented 5 years ago

把 onCreateViewHolder 中的 recyclerview 替换成 其他控件 也没问题。

你把你的HomeHorizontalAdapter 拿出来我再看看

oksimple commented 5 years ago

public class HomeHorizontalAdapter extends BaseQuickAdapter<String, BaseViewHolder> {

public HomeHorizontalAdapter(List<String> data) {
    super(R.layout.adapter_popular_item, data);
}

@Override
protected void convert(BaseViewHolder helper, String s) {
    helper.setText(R.id.name_tv, s);
}

}

oksimple commented 5 years ago

这个 HomeHorizontalAdapter 我换成没有封装过的 adapter 也不行。

oksimple commented 5 years ago

你上面的代码 我试了 还是不行

oksimple commented 5 years ago

都是 match_parent

XXQAQ commented 5 years ago

你上面的代码 我试了 还是不行

R.layout.adapter_popular_item的 根布局 的Width是多少

XXQAQ commented 5 years ago

都是 match_parent

你先用wrap 试试

oksimple commented 5 years ago

wrap_content 或者 固定值 都不行

oksimple commented 5 years ago

我开始怀疑是动态高度引起的,结果 我换成了 ScrollView 就没问题

XXQAQ commented 5 years ago

你的意思是,把RecyclerVIew换成ScrollView ?就没问题

oksimple commented 5 years ago

XXQAQ commented 5 years ago

再试一个办法 ,这里的RecyclerView不使用new的方式构造 ,你自己写个布局文件 ,根布局是RecyclerView并且宽高写死,然后直接用布局构造器构造出来

oksimple commented 5 years ago

好的

XXQAQ commented 5 years ago

最好

好的 记得给布局文件中的RecyclerVIew设置个背景色, 最好是大红色

oksimple commented 5 years ago

public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { RecyclerView rv = (RecyclerView) View.inflate(parent.getContext(), R.layout.test, null); rv.setLayoutManager(new GridLayoutManager(parent.getContext(), 1, RecyclerView.HORIZONTAL, false)); if (decoration != null) rv.addItemDecoration(decoration); rv.setAdapter(adapter); return new RecyclerView.ViewHolder(rv) { }; }

oksimple commented 5 years ago

还是不行。。。

oksimple commented 5 years ago

<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="200dp" android:layout_height="200dp" android:background="#FA0000">

</android.support.v7.widget.RecyclerView>

XXQAQ commented 5 years ago

还是不行。。。

背景颜色都没有吗,那你留个QQ

oksimple commented 5 years ago

568330858

Lyon1994 commented 5 years ago

BaseViewHolder需要设置禁止回收标识,否则容易重复创建

mallxiaodoudou commented 4 years ago

大神 我问一下 我现在用了你的这个Adapter, 我横向的布局使用的VLayoutHorizontalAdapter内部使用默认的Adapter 。 因为点击之后变成选中,我需要Adapter刷新 我只能刷新VLayoutHorizontalAdapter才行 内部的Adapter刷新不起作用,但是刷新整个VLayoutHorizontalAdapter的话 会把整个RV都刷新了 我的滚动状态没了 只要刷新就默认回到0的索引了

VLayoutHorizontalAdapter内部的这个RecyclerView.ScrolltoPosition(5) 这个也没有作用 我怎么让这个内部的Recyclerview去滚动呢?..苦恼 我感觉内部的这个scrolltoPosition已经生效了 但是VLayoutHorizontalAdapter没有刷新它不展示出来 但是我一刷新它就回到了0的索引 滚动就白滚动了。 怎么能实现这种滚动效果呢?

shiner0 commented 3 years ago

你好,按照你的这个方式写了之后 把页面来回滑动几次之后 页面在这个横向布局的地方 就再也滑动不到顶部了,内部嵌套的rv 用的时最外面的服用回收池

XXQAQ commented 3 years ago

你好,按照你的这个方式写了之后 把页面来回滑动几次之后 页面在这个横向布局的地方 就再也滑动不到顶部了,内部嵌套的rv 用的时最外面的服用回收池

复用池不用混用,不同类型itemview的复用池也理应属于不同对象

shiner0 commented 3 years ago

你好,按照你的这个方式写了之后放在页面来回滑动一下之后之后页面在这个横向布局的地方就再也滑动不到顶部了,内部嵌套的rv用的时最外面的采用回收池

过多池不用混用,不同类型itemview的重叠池也理应属于不同对象

这种情况是不是只需要最外层的那个设置了复用池就可以,里面item的recycleview 和平时一样正常使用就可以