Android 使用基于领域的适配器进行RecyclerView拖放

Android 使用基于领域的适配器进行RecyclerView拖放,android,android-recyclerview,realm,Android,Android Recyclerview,Realm,我是Android新手,但在阅读了一些教程后,我成功地编写了一个简单的应用程序,通过扩展realmrecyclererviewadapter,使用recyclererview和领域数据 我知道默认的动画师需要稳定的id,所以我为我的实体添加了一个唯一的id。除了拖放之外,所有操作似乎都很正常(滑动以删除、添加、所有领域操作)。嗯,这意味着数据和ui保持一致,但动画看起来很奇怪,我只能将项目向下移动一个位置。 一幅画抵得上千言万语,所以它就在这里: 我想我还需要粘贴代码。我尽量把它缩短 publ

我是Android新手,但在阅读了一些教程后,我成功地编写了一个简单的应用程序,通过扩展
realmrecyclererviewadapter
,使用
recyclererview
和领域数据 我知道默认的动画师需要稳定的id,所以我为我的实体添加了一个唯一的id。除了拖放之外,所有操作似乎都很正常(滑动以删除、添加、所有领域操作)。嗯,这意味着数据和ui保持一致,但动画看起来很奇怪,我只能将项目向下移动一个位置。
一幅画抵得上千言万语,所以它就在这里:

我想我还需要粘贴代码。我尽量把它缩短

public class MainActivity extends AppCompatActivity implements OnStartDragListener {
    private ItemTouchHelper touchHelper;
    private Realm realm;
    private TestRecyclerViewAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // Irrelevant init stuff stripped

        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

        adapter = new TestRecyclerViewAdapter(this, realm.where(Item.class)
                                                         .findAll()
                                                         .sort(Item.INDEX));
        recyclerView.setAdapter(adapter);

        ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(adapter);
        touchHelper = new ItemTouchHelper(callback);
        touchHelper.attachToRecyclerView(recyclerView);
    }

    @Override
    public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
        touchHelper.startDrag(viewHolder);
    }

    // not sure how this method should be implemented
    public void moveItem(Item item, final int fromPosition, final int toPosition) {
        final int index = item.index;
        realm.executeTransaction(new Realm.Transaction() {
            @Override
            public void execute(Realm realm) {
                Item item = realm.where(Item.class).equalTo(Item.INDEX, index).findFirst();
                if (fromPosition < toPosition) {
                    RealmResults<Item> results = realm.where(Item.class)
                                                      .greaterThan(Item.INDEX, fromPosition)
                                                      .lessThanOrEqualTo(Item.INDEX, toPosition)
                                                      .findAll();
                    for (int i = 0; i < results.size(); i++) {
                        results.get(i).index -= 1;
                    }
                } else {
                    RealmResults<Item> results = realm.where(Item.class)
                                                      .greaterThanOrEqualTo(Item.INDEX, toPosition)
                                                      .lessThan(Item.INDEX, fromPosition)
                                                      .findAll();
                    for (int i = 0; i < results.size(); i++) {
                        results.get(i).index += 1;
                    }
                }
                item.index = toPosition;
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        realm.close();
    }
}


我为发布这么多的代码感到内疚…

您的问题源于这样一个事实,即
RealmRecyclServiceAdapter
注册了一个
RealmChangeListener
,它调用
适配器.notifyDataSetChanged()
,它覆盖了所有RecyclerView动画

一种可能的解决方法是使用常规的RecycleServiceAdapter,当您使用UI线程事务处理领域的元素时,您可以

类TestRecycleServiceAdapter扩展了RecycleView.Adapter{ @凌驾 公共布尔onItemMove(int-fromPosition,int-toPosition){
activity.moveItem(getData().get(fromPosition)、fromPosition、TopoPosition);//我接受了你的建议,但我做的有点不同。我使用了常规的
RecycleServiceAdapter
并将领域操作移到了适配器上,到目前为止,它还在工作。
public class Item extends RealmObject {
    public static final String INDEX = "index";
    public static final String TEXT = "text";
    public static final String ID = "id";

    @PrimaryKey
    public long id;
    @Index
    public int index;
    public String text;
}
interface OnStartDragListener {
    void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
class TestRecyclerViewAdapter extends RealmRecyclerViewAdapter<Item,
        TestRecyclerViewAdapter.EditInfoViewHolder> implements ItemTouchHelperAdapter {

    private final static String TAG = TestRecyclerViewAdapter.class.getName();
    private final MainActivity activity;

    public TestRecyclerViewAdapter(@NonNull MainActivity activity, @Nullable
            OrderedRealmCollection<Item> data) {
        super(activity, data, true);
        this.activity = activity;
        setHasStableIds(true);
    }

    @Override
    public long getItemId(int index) {
        return getData().get(index).id;
    }

    @Override
    public EditInfoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = inflater.inflate(R.layout.item, parent, false);
        return new EditInfoViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final EditInfoViewHolder holder, int position) {
        Item obj = getData().get(position);
        holder.data = obj;
        holder.text.setText(obj.text);
        holder.handle.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
                    activity.onStartDrag(holder);
                }
                return false;
            }
        });
    }

    @Override
    public boolean onItemMove(int fromPosition, int toPosition) {
        activity.moveItem(getData().get(fromPosition), fromPosition, toPosition);
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    class EditInfoViewHolder extends RecyclerView.ViewHolder {
        final TextView text;
        final ImageView handle;

        public Item data;
        public EditInfoViewHolder(View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.text);
            handle = (ImageView) itemView.findViewById(R.id.handle);
        }

    }
}
interface ItemTouchHelperAdapter {
    boolean onItemMove(int fromPosition, int toPosition);
}
class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperAdapter adapter;

    public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        this.adapter = adapter;
    }

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

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

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = 0;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
        if (source.getItemViewType() != target.getItemViewType()) {
            return false;
        }
        adapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    }
}
class TestRecyclerViewAdapter extends RecyclerView.Adapter<...> {

@Override
public boolean onItemMove(int fromPosition, int toPosition) {
    activity.moveItem(getData().get(fromPosition), fromPosition, toPosition); // <-- refresh in there
    notifyItemMoved(fromPosition, toPosition);
    return true;
}

public void moveItem(Item item, final int fromPosition, final int toPosition) {
    final int index = item.index;
    realm.executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            Item item = realm.where(Item.class).equalTo(Item.INDEX, index).findFirst();
            if (fromPosition < toPosition) {
                RealmResults<Item> results = realm.where(Item.class)
                                                  .greaterThan(Item.INDEX, fromPosition)
                                                  .lessThanOrEqualTo(Item.INDEX, toPosition)
                                                  .findAll();
                for (int i = 0; i < results.size(); i++) {
                    results.get(i).index -= 1;
                }
            } else {
                RealmResults<Item> results = realm.where(Item.class)
                                                  .greaterThanOrEqualTo(Item.INDEX, toPosition)
                                                  .lessThan(Item.INDEX, fromPosition)
                                                  .findAll();
                for (int i = 0; i < results.size(); i++) {
                    results.get(i).index += 1;
                }
            }
            item.index = toPosition;
        }
    });
    RealmRefresh.refreshRealm(realm);
}