【问题标题】:StaggeredGridLayoutManager reorders itemsStaggeredGridLayoutManager 重新排序项目
【发布时间】:2017-06-16 13:45:04
【问题描述】:

我的项目有不同的布局,有时我通过拖动布局中的项目在 RecyclerView 顶部创建一个或多个间隙。当我滚动回 RecyclerView 的顶部时,一些项目被重新排序,并且它们填补了空白。 此处捕获行为:

填补空白是可以的。当项目在拖动过程中改变位置时也可以。问题在于滚动到顶部。滚动结束时会发生重新排序 - 我没有触摸屏幕。

这就是我创建回收视图和布局管理器的方式

    recyclerView = (RecyclerView)layout.findViewById(R.id.recycler_view);

    stagaggeredGridLayoutManager =
        new StaggeredGridLayoutManager(
            getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 3 : 2, StaggeredGridLayoutManager.VERTICAL);

    recyclerView.setLayoutManager(stagaggeredGridLayoutManager);

    stagaggeredList = getListItemData();

    StatisticsGridViewAdapter rcAdapter = new StatisticsGridViewAdapter(this.getActivity(), stagaggeredList, recyclerView);

    ItemTouchHelper.Callback callback = new StatisticsTouchHelperCallback(rcAdapter);
    touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(recyclerView);

    recyclerView.setAdapter(rcAdapter);

ItemTouchHelper 类

public class StatisticsTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperAdapter touchHelperAdapter;


    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return false;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP   | ItemTouchHelper.DOWN |
            ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;

        int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
        RecyclerView.ViewHolder target) {
        touchHelperAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        touchHelperAdapter.onItemDismiss(viewHolder.getAdapterPosition());
    }

    public StatisticsTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        touchHelperAdapter = adapter;
    }
}

RecyclerView 适配器

public class StatisticsGridViewAdapter extends RecyclerView.Adapter<StatisticsGridItemViewHolder> implements ItemTouchHelperAdapter {

    private List<Statistic> itemList;
    private Context context;

    @Override
    public StatisticsGridItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View layoutView = LayoutInflater.from(parent.getContext()).inflate(itemList.get(viewType).getStatisticType().getStringResourcesId(), null);
        StatisticsGridItemViewHolder rcv = new StatisticsGridItemViewHolder(layoutView, viewType);
        return rcv;
    }

    @Override
    public void onBindViewHolder(final StatisticsGridItemViewHolder holder, int position) {
        holder.getMenu().setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                PopupMenu popup = new PopupMenu(v.getContext(), holder.getMenu());
                popup.getMenuInflater().inflate(R.menu.statistics__widget__popup_menu, popup.getMenu());
                Menu menu = popup.getMenu();
                MenuItem item = menu.add(R.string.statistics__widget__menu_item__pin_to_dashboard);
                //item.setOnMenuItemClickListener()
                popup.show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return this.itemList.size();
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(itemList, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(itemList, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public void onItemDismiss(int position) {
        itemList.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public int getItemViewType(int position) {return itemList.get(position).getStatisticType().getPosition();
    }

    public StatisticsGridViewAdapter(Context context, List<Statistic> itemList) {
        this.itemList = itemList;
        this.context = context;
    }
}
interface ItemTouchHelperAdapter {

    boolean onItemMove(int fromPosition, int toPosition);

    void onItemDismiss(int position);
}

现在我使用 12 种具有相同结构的不同布局。只有高度不同才能模拟最终的小部件。

项目布局示例

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <LinearLayout
        android:id="@+id/statistics__widget__main_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/order_tile_final"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="5dp"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="7dp"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="17dp"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/widget_title"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:text="@string/statistics__widget__forms_filled_title"
                style="@style/tablet_common_font__main_3"
                android:paddingTop="10dp"
                android:layout_weight="1"/>
            <ImageView
                android:id="@+id/widget_menu"
                android:layout_width="wrap_content"
                android:layout_height="23dp"
                android:layout_marginTop="7dp"
                android:paddingTop="5dp"
                android:layout_marginRight="8dp"
                android:src="@drawable/a_menu_dark"/>
        </LinearLayout>
        <TextView
            android:id="@+id/widget_value"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/tablet_common_font__headline_2"
            android:layout_marginLeft="17dp"
            android:layout_marginBottom="6dp"/>
    </LinearLayout>
</LinearLayout>

【问题讨论】:

  • @Nikola Anusev 只是一个改进 remove recyclerView.setHasFixedSize(true);原因是屏幕上绘制的项目的宽度和高度不相等。
  • 请提供项目布局。
  • 我添加了项目布局示例
  • @MichalZhradnkNono3551 你找到解决方案了吗?我有点面临同样的问题
  • @miraquee 我没有,它与我不再相关。但我相信您可以找到用于制作此类仪表板的库,这些库可能对您有用。就我而言,我不能使用这样的东西。

标签: android android-layout android-recyclerview staggeredgridlayout


【解决方案1】:

最好的解决方案是创建您的 StaggeredLayoutMenager

class YourStaggeredLayoutManager(count:Int, orientation:Int) : StaggeredGridLayoutManager(count,orientation) {
    override fun onItemsUpdated(
            recyclerView: RecyclerView,
            positionStart: Int,
            itemCount: Int,
            payload: Any?
    ) {}

    override fun onItemsUpdated(recyclerView: RecyclerView, positionStart: Int, itemCount: Int) {}
}

【讨论】:

    【解决方案2】:

    您必须扩展 Recycler View 才能启用重新排序功能。

    请点击以下链接: https://gist.github.com/mohlendo/68b7e2f89d0b1b354abe

    对于完整示例,请使用以下链接: https://github.com/mohlendo/ReorderRecyclerView

    【讨论】:

    • 示例不适用于具有不同布局的项目。
    【解决方案3】:

    如果我了解您的问题,我之前曾在 Recyclerview 工作过,我认为以下内容将解决该问题。

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(itemList, i, i + 1);
                notifyItemMoved(i, i+1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(itemList, i, i - 1);
                notifyItemMoved(i, i-1);
            }
        }
    
        return true;
    }
    

    如果有任何问题或我对您的问题的理解有误,请告诉我。

    最佳推荐

    【讨论】:

    • 这并没有解决问题。滚动到顶部后,项目仍在重新排序。
    【解决方案4】:

    我认为这是StaggeredGridLayoutManager的常见行为:

    当滚动状态更改为 SCROLL_STATE_IDLE 时,StaggeredGrid 将检查是否存在间隙,因为满跨项。如果找到,它将重新布局并使用动画将项目移动到正确的位置。

    您可以通过将策略更改为GAP_HANDLING_NONE 来停止填空行为:

    stagaggeredGridLayoutManager.setGapStrategy(
            StaggeredGridLayoutManager.GAP_HANDLING_NONE);
    

    【讨论】:

    • 感谢您的回复。我知道这个设置,但它不会解决我的问题。预期的情况是,如果项目仅上下移动以填补空白。
    猜你喜欢
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    • 2015-02-22
    • 2016-05-04
    相关资源
    最近更新 更多