对话框中的RecyclerView -> 拖放(交换)动画卡顿

4

我在DialogFragment(确切地说是AlertDialog)中使用带有拖放功能的RecyclerViewItemTouchHelper.Callback -> onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target))。

问题在于,当我上下移动被举起(拖动)的项目时,动画会出现滞后。我尝试使用相同的RecyclerViewActivity中的Fragment中运行,并且运行得很平稳。我怀疑问题在于Activity占据了整个屏幕,而DialogFragment没有(模糊的背景显示在对话框周围)。我认为在AlertDialog中移动项目时进行了一些额外的计算。

编辑过的

我的适配器类:

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.TabItemViewHolder> implements ItemTouchHelperAdapter {

    private List<Tab> tabs;

    public ListAdapter(List<Tab> tabs) {
        this.tabs = tabs;
    }

    @Override
    public TabItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list_tab_list, parent, false);
        return new TabItemViewHolder(itemView);
    }


    @Override
    public void onBindViewHolder(TabItemViewHolder holder, final int position) {
        Tab tab = tabs.get(position);
        holder.tvTabName.setText(tab.getTabCategory().toString());
    }


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

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

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

    public static class TabItemViewHolder extends RecyclerView.ViewHolder {

        public TextView tvTabName;

        public TabItemViewHolder(final View itemView) {
            super(itemView);

            tvTabName = (TextView) itemView.findViewById(R.id.cl__tv_tab_name);


        }
    }
}

函数void onItemMove(int fromPosition, int toPosition)void onItemDismiss(int position)是从ItemTouchHelper调用的。

DialogFragment类:

public Dialog onCreateDialog(Bundle savedInstanceState) {
    final RecyclerView recyclerView = (RecyclerView) getActivity().getLayoutInflater().inflate(R.layout.recycler_view, null);

    ListAdapter listAdapter = new ListAdapter (tabs);
    recyclerView.setAdapter(listAdapter );
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    SimpleItemTouchHelperCallback simpleItemTouchHelperCallback = new SimpleItemTouchHelperCallback(listAdapter);
    ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchHelperCallback);
    itemTouchHelper.attachToRecyclerView(recyclerView);

    return new AlertDialog.Builder(getActivity())
            .setTitle(R.string.title)
            .setView(recyclerView)
            .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {

                }
            })
            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                }
            }).create();

}

2
你能添加你可能尝试过的代码吗? - Nilesh Singh
@NileshSingh 这是一个标准的 RecyclerView.Adapter 类,它实现了项目移动和删除功能。我确定问题不在这里,因为这个适配器在 Fragment/Activity 中运行良好,但在 DialogFragment 中使用时却出现延迟。 - AppiDevo
您可以查看此示例 -> RecycleViewInDialogFragment - Cabezas
@Cabezas 我检查了代码。我将创建适配器的步骤移动到了 onCreateDialog 中,并使用了 AlertDialog.Builder,将 RecyclerView 设置为 setView,但它仍然像我的代码一样卡顿 :) 顺便说一下,它在低中端设备上(如1 GHz,2核)会卡顿。当然,在更快的设备/模拟器上它运行得更好。 - AppiDevo
1个回答

0

问题似乎出在您的ItemTouchHelper.Callback实现上。请尝试使用以下类重新实现拖放功能。

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {

private final ItemTouchHelperAdapter mAdapter;

public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
    mAdapter = adapter;
}

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



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

@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {

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

}

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

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

}

这是ItemTouchHelper.Callback的自定义实现,将启用拖放功能。您还需要在适配器上实现一个接口来更新数据的状态。

public interface ItemTouchHelperAdapter {


void onItemMove(int fromPosition, int toPosition);

void onItemDismiss(int position);

}

/** * 监听从{@link ItemTouchHelper.Callback}移动或解除事件的接口。 * * 作者:Paul Burke(ipaulpro) */

下面还提到了接口的适配器实现。

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

@Override
public void onItemMove(int fromPosition, int toPosition) {

    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(data, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(data, i, i - 1);
        }
    }
    notifyItemMoved(fromPosition, toPosition);

}

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

/****对话框片段***/

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     super.onCreateView(inflater, container, savedInstanceState);
    View root = inflater.inflate(R.layout.dialog_fragment_layout,container,false);
    list = (RecyclerView) root.findViewById(R.id.list);
    data = getResources().getStringArray(R.array.list);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
    linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    list.setLayoutManager(linearLayoutManager);
    ArrayList<String> listData = new ArrayList<>();
    listData.addAll(Arrays.asList(data));
    listAdapter = new ListAdapter(getActivity(),listData);
    list.setAdapter(listAdapter);
    SimpleItemTouchHelperCallback callback = new SimpleItemTouchHelperCallback(listAdapter);
    ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
    touchHelper.attachToRecyclerView(list);
    return root;
}

我已经使用了Paul Burke的ItemTouchHelper.Callback实现。我确信问题不在我的实现上,因为正如我所说,我的适配器在全屏幕活动/片段列表中运行良好。我认为解决方案将基于在DialogFragment(我的RecylerView列表的容器)中设置某种额外信息。 - AppiDevo
我不这么认为。我创建了一个普通的对话框片段,并实现了Paul Burke的拖放功能。请查看上面对话框片段的代码。 - Puneet Kashyap
尝试使用带有标题和按钮的onCreateDialog(对话框)以及AlertDialog.Builder setView(recylerView),但由于我的代码滞后,它也会出现滞后。(1GHz - 2核设备,在模拟器上运行良好) - AppiDevo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接