youlookwhat / ByRecyclerView

🔥 RecyclerView 下拉刷新、上拉松手/自动加载更多、item点击/长按、item局部刷新、头布局/尾布局/状态布局、万能分割线、Skeleton骨架图、极简adapter、嵌套滑动置顶
https://youlookwhat.github.io/ByRecyclerView
Apache License 2.0
798 stars 139 forks source link

瀑布流添加分割线的问题 #43

Closed jiqianwen closed 2 years ago

jiqianwen commented 2 years ago

首次加载动态获取item宽度按比例计算item高度,item的左右间距会有问题,重新刷新一次数据就好了

youlookwhat commented 2 years ago

能不能给一个录屏或者对应代码呢;demo中给出的示例有问题吗,可以的话我需要对着问题调整一下

jiqianwen commented 2 years ago

能不能给一个录屏或者对应代码呢;demo中给出的示例有问题吗,可以的话我需要对着问题调整一下

已经在demo中复现,以下是涉及到的类代码

GridAdapter public class GridAdapter extends BaseRecyclerAdapter {

private boolean isStaggered = false;

public GridAdapter() {
    super(R.layout.item_grid);
}

public GridAdapter(List<DataItemBean> data) {
    super(R.layout.item_grid, data);
}

@Override
protected void bindView(final BaseByViewHolder<DataItemBean> holder, final DataItemBean bean, final int position) {
    if (isStaggered) {
        final TextView tvTitle = holder.getView(R.id.tv_title);

        tvTitle.post(new Runnable() {
            @Override
            public void run() {
                float widthRatio = bean.getWidth() / (float) tvTitle.getWidth();
                ViewGroup.LayoutParams layoutParams = tvTitle.getLayoutParams();
                layoutParams.height = (int) (bean.getHeight() / widthRatio);
                tvTitle.setLayoutParams(layoutParams);
                tvTitle.setText("" + position);
            }
        });
    }
}

public boolean isStaggered() {
    return isStaggered;
}

public void setStaggered(boolean staggered) {
    isStaggered = staggered;
}

}

================================================================================

DataItemBean public class DataItemBean {

private String title;
private String content;
private String des;

private String image;
private int width = 0;
private int height = 0;

private String type;
private Class<?> cls;

private int isZan;
private int isCollect;

public DataItemBean() {
}

public DataItemBean(String title, Class<?> cls) {
    this.title = title;
    this.cls = cls;
}

public int getIsZan() {
    return isZan;
}

public void setIsZan(int isZan) {
    this.isZan = isZan;
}

public int getIsCollect() {
    return isCollect;
}

public void setIsCollect(int isCollect) {
    this.isCollect = isCollect;
}

public String getDes() {
    return des;
}

public void setDes(String des) {
    this.des = des;
}

public String getContent() {
    return content;
}

public void setContent(String content) {
    this.content = content;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public Class<?> getCls() {
    return cls;
}

public void setCls(Class<?> cls) {
    this.cls = cls;
}

public String getTitle() {
    return title;
}

public DataItemBean setTitle(String title) {
    this.title = title;
    return this;
}

public int getWidth() {
    return width;
}

public void setWidth(int width) {
    this.width = width;
}

public int getHeight() {
    return height;
}

public void setHeight(int height) {
    this.height = height;
}

public String getImage() {
    return image;
}

public void setImage(String image) {
    this.image = image;
}

}

==============================================================================

item_grid.xml <?xml version="1.0" encoding="utf-8"?>

==============================================================================

GridFragment public class GridFragment extends BaseFragment {

private static final String TYPE = "mType";
private String mType = "Android";
private boolean mIsPrepared;
private boolean mIsFirst = true;
private GridAdapter mAdapter;
private ByRecyclerView recyclerView;
private int page = 1;

@Override
public void onAttach(Context context) {
    super.onAttach(context);
}

public static GridFragment newInstance(String type) {
    GridFragment fragment = new GridFragment();
    Bundle args = new Bundle();
    args.putString(TYPE, type);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mType = getArguments().getString(TYPE);
    }
}

@Override
public int setContent() {
    return R.layout.fragment_refresh;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // 准备就绪
    mIsPrepared = true;
    initAdapter();
}

@Override
protected void loadData() {
    if (!mIsPrepared || !mIsVisible || !mIsFirst) {
        return;
    }
    initAdapter();
}

private void initAdapter() {
    recyclerView = getView(R.id.recyclerView);

    final List<DataItemBean> dataList = new ArrayList<>();

    DataItemBean bean = new DataItemBean();
    bean.setWidth(700);
    bean.setHeight(1244);
    dataList.add(bean);

    DataItemBean bean1 = new DataItemBean();
    bean1.setWidth(579);
    bean1.setHeight(697);
    dataList.add(bean1);

    DataItemBean bean3 = new DataItemBean();
    bean3.setWidth(652);
    bean3.setHeight(958);
    dataList.add(bean3);

    DataItemBean bean4= new DataItemBean();
    bean4.setWidth(1080);
    bean4.setHeight(1439);
    dataList.add(bean4);

    mAdapter = new GridAdapter();

    if ("grid".equals(mType)) {
        // 宫格
        GridLayoutManager gridLayoutManager = new GridLayoutManager(activity, 6);
        recyclerView.setLayoutManager(gridLayoutManager);
        // 四周也有间距
        GridSpaceItemDecoration itemDecoration = new GridSpaceItemDecoration(
                DensityUtil.dip2px(activity, 10), true);
        // 去掉首尾的分割线 (刷新头部和加载更多尾部)
        recyclerView.addItemDecoration(itemDecoration.setNoShowSpace(2, 1));

    } else {
        mAdapter.setStaggered(true);
        // 瀑布流
        StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);

        recyclerView.setAdapter(mAdapter);

        // 四周没有间距
        GridSpaceItemDecoration itemDecoration = new GridSpaceItemDecoration(DensityUtil.dip2px(activity, 18));
        recyclerView.addItemDecoration(itemDecoration);

        mAdapter.setNewData(dataList);
    }

// recyclerView.addHeaderView(R.layout.layout_header_view); // recyclerView.setAdapter(mAdapter); recyclerView.setOnLoadMoreListener(new ByRecyclerView.OnLoadMoreListener() { @Override public void onLoadMore() { if (page == 4) { recyclerView.loadMoreEnd(); return; } page++; mAdapter.addData(DataUtil.getMore(activity, 20, page)); recyclerView.loadMoreComplete(); } }, 1000); recyclerView.setOnItemClickListener(new ByRecyclerView.OnItemClickListener() { @Override public void onClick(View v, int position) { DataItemBean itemData = mAdapter.getItemData(position); // ToastUtil.showToast(itemData.getTitle()); // recyclerView.setRefreshing(true); } }); recyclerView.setOnRefreshListener(new ByRecyclerView.OnRefreshListener() { @Override public void onRefresh() { recyclerView.postDelayed(new Runnable() { @Override public void run() { page = 1; mAdapter.setNewData(dataList); } }, 1000); } }); mIsFirst = false; } }

youlookwhat commented 2 years ago

是的,逻辑也情有可原,因为相当于你是在渲染后再设置的item宽高,那就要再刷新一次设置左右间距。

我觉得正常的逻辑应该是在渲染前就得到了要设置的宽高,不额外在holder获取宽高,

@Override
protected void bindView(final BaseByViewHolder<DataItemBean> holder, final DataItemBean bean, final int position) {
    if (isStaggered) {
        final TextView tvTitle = holder.getView(R.id.tv_title);

        ViewGroup.LayoutParams layoutParams = tvTitle.getLayoutParams();
        layoutParams.height = (int) (bean.getHeight() / widthRatio);
        tvTitle.setLayoutParams(layoutParams);
    }
}

这里的比例widthRatio应该是直接获取的,不应该在bindView获取。你可能要换一种做法了,试想一下,如果获取widthRatio的时间很长,那么列表就会跳动,也是不友好的。

你可以将widthRatio写死,然后试一下,看还有没有你说的这种需要额外notify的情况

jiqianwen commented 2 years ago

是的,逻辑也情有可原,因为相当于你是在渲染后再设置的item宽高,那就要再刷新一次设置左右间距。

我觉得正常的逻辑应该是在渲染前就得到了要设置的宽高,不额外在holder获取宽高,

@Override
protected void bindView(final BaseByViewHolder<DataItemBean> holder, final DataItemBean bean, final int position) {
    if (isStaggered) {
        final TextView tvTitle = holder.getView(R.id.tv_title);

        ViewGroup.LayoutParams layoutParams = tvTitle.getLayoutParams();
        layoutParams.height = (int) (bean.getHeight() / widthRatio);
        tvTitle.setLayoutParams(layoutParams);
    }
}

这里的比例widthRatio应该是直接获取的,不应该在bindView获取。你可能要换一种做法了,试想一下,如果获取widthRatio的时间很长,那么列表就会跳动,也是不友好的。

你可以将widthRatio写死,然后试一下,看还有没有你说的这种需要额外notify的情况

我现在就是直接按照设计图的宽度来弄了,原本是打算动态获取到实际的宽度再计算等比的

youlookwhat commented 2 years ago

是的,逻辑也情有可原,因为相当于你是在渲染后再设置的item宽高,那就要再刷新一次设置左右间距。 我觉得正常的逻辑应该是在渲染前就得到了要设置的宽高,不额外在holder获取宽高,

@Override
protected void bindView(final BaseByViewHolder<DataItemBean> holder, final DataItemBean bean, final int position) {
    if (isStaggered) {
        final TextView tvTitle = holder.getView(R.id.tv_title);

        ViewGroup.LayoutParams layoutParams = tvTitle.getLayoutParams();
        layoutParams.height = (int) (bean.getHeight() / widthRatio);
        tvTitle.setLayoutParams(layoutParams);
    }
}

这里的比例widthRatio应该是直接获取的,不应该在bindView获取。你可能要换一种做法了,试想一下,如果获取widthRatio的时间很长,那么列表就会跳动,也是不友好的。 你可以将widthRatio写死,然后试一下,看还有没有你说的这种需要额外notify的情况

我现在就是直接按照设计图的宽度来弄了,原本是打算动态获取到实际的宽度再计算等比的

你将widthRatio写死可以吗,简而言之不能有这样的操作:

tvTitle.post(new Runnable() {
            @Override
            public void run() {
                float widthRatio = bean.getWidth() / (float) tvTitle.getWidth();
                ViewGroup.LayoutParams layoutParams = tvTitle.getLayoutParams();
                layoutParams.height = (int) (bean.getHeight() / widthRatio);
                tvTitle.setLayoutParams(layoutParams);
                tvTitle.setText("" + position);
            }
        });

如果写死可以,那么有三种方案可以解决你的问题: 1.和现在一样,需要额外notify一次 2.更改你的代码实现方案,将widthRatio在adapter构造方法里就计算出来,在bindView里直接使用 3.跟产品沟通item的高度,达到在bindView之前就将宽高得到的目的

可以给个参考,我们公司一般是图片的宽高是接口给的,文字是不做具体的高度限制。不会在adapter里再额外有获取宽高的行为:tvTitle.getWidth()

youlookwhat commented 2 years ago

已使用固定高度解决,有问题再提~