FastAdapter:滑动后不显示“撤消”按钮

时间:2018-11-02 23:57:15

标签: android android-recyclerview swipe fastadapter

我正在尝试在带有modeladapter的列表上使用swipeCallback。为了使其工作,我剥离了所有自定义项并对其进行建模,使其接近示例应用程序,但是这种组合产生了不允许撤消的错误。当我滑动时,会发生这种情况:

enter image description here

滑动有效,但未显示撤消图标。有什么想法我做错了吗?底层片段是这样的:

public class EditFragment extends Fragment implements ItemTouchCallback, SimpleSwipeCallback.ItemSwipeCallback {

    private FragmentEditBinding oBinding;
    private SongViewModel oViewModel;
    //save our FastAdapter
    private FastAdapter fastAdapter;
    private ModelAdapter<ModelSongCounter, ModelItemView> itemAdapter;
    //drag & drop
    private SimpleDragCallback touchCallback;
    private ItemTouchHelper touchHelper;

    public EditFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        //init Databinding
        oBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_edit, container, false);//.setContentView(getActivity(), R.layout.fragment_main);

        //LayoutInflaterCompat.setFactory(getLayoutInflater(), new IconicsLayoutInflater(getActivity()));

        //style our ui
        new MaterializeBuilder().withActivity(getActivity()).build();

        //adapters
        //FastScrollIndicatorAdapter fastScrollIndicatorAdapter = new FastScrollIndicatorAdapter();
        itemAdapter = new ModelAdapter<>(new IInterceptor<ModelSongCounter, ModelItemView>() {
            @Override
            public ModelItemView intercept(ModelSongCounter iconModel) {
                return new ModelItemView(iconModel);
            }
        });

        //create our FastAdapter which will manage everything
        fastAdapter = FastAdapter.with(Arrays.asList(itemAdapter));
        fastAdapter.withSelectable(true);

        //get our recyclerView and do basic setup
        //RecyclerView rv = oBinding.SongRecyclerView;
        oBinding.SongRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        //oBinding.SongRecyclerView.setItemAnimator(new SlideDownAlphaAnimator());
        oBinding.SongRecyclerView.setAdapter(fastAdapter);

        //get ViewModels from Provider
        oViewModel = ViewModelProviders.of(getActivity()).get(SongViewModel.class);

        //get rid of the annoying blink
        oBinding.SongRecyclerView.setItemAnimator(null);

        //add Observer to ViewModel
        // The onChanged() method fires when the observed data changes and the activity is
        // in the foreground.
        oViewModel.getAllCatsLive().observe(this, new Observer<List<ModelSongCounter>>() {
            @Override
            public void onChanged(@Nullable List<ModelSongCounter> modelSongCounters) {
                itemAdapter.set(modelSongCounters);
            }
        });

        fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {

            @Nullable
            @Override
            public View onBind(@NonNull RecyclerView.ViewHolder viewHolder) {
                if (viewHolder instanceof ModelItemView.ViewHolder) {
                    return ((ModelItemView.ViewHolder) viewHolder).Minus;
                }
                return null;
            }

            @Override
            public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
                //react on the click event
                oViewModel.decrement(item.getModel().uid);
            }
        });

        fastAdapter.withEventHook(new ClickEventHook<ModelItemView>() {

            @Nullable
            @Override
            public View onBind(@NonNull RecyclerView.ViewHolder viewHolder) {
                if (viewHolder instanceof ModelItemView.ViewHolder) {
                    return ((ModelItemView.ViewHolder) viewHolder).Plus;
                }
                return null;
            }

            @Override
            public void onClick(View v, int position, FastAdapter<ModelItemView> fastAdapter, ModelItemView item) {
                //react on the click event
                oViewModel.increment(item.getModel().uid);
            }
        });

        //restore selections (this has to be done after the items were added
        fastAdapter.withSavedInstanceState(savedInstanceState);

        //Swipable stuff within OnCreateView

        Drawable leaveBehindDrawableLeft = new IconicsDrawable(getContext())
                .icon(MaterialDesignIconic.Icon.gmi_delete)
                .color(Color.WHITE)
                .sizeDp(24);
        Drawable leaveBehindDrawableRight = new IconicsDrawable(getContext())
                .icon(MaterialDesignIconic.Icon.gmi_archive)
                .color(Color.WHITE)
                .sizeDp(24);

        touchCallback = new SimpleSwipeDragCallback(
                this,
                this,
                leaveBehindDrawableLeft,
                ItemTouchHelper.LEFT,
                ContextCompat.getColor(getContext(), R.color.md_red_900)
        )
                .withBackgroundSwipeRight(ContextCompat.getColor(getContext(), R.color.md_blue_900))
                .withLeaveBehindSwipeRight(leaveBehindDrawableRight);

        touchHelper = new ItemTouchHelper(touchCallback); // Create ItemTouchHelper and pass with parameter the SimpleDragCallback
        touchHelper.attachToRecyclerView(oBinding.SongRecyclerView); // Attach ItemTouchHelper to RecyclerView

        //restore selections (this has to be done after the items were added
        fastAdapter.withSavedInstanceState(savedInstanceState);

        return oBinding.getRoot();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        //add the values which need to be saved from the adapter to the bundle
        outState = fastAdapter.saveInstanceState(outState);
        super.onSaveInstanceState(outState);
    }

    //Swipable...and probably relevant for expandables, since there is TouchOnMove
    @Override
    public boolean itemTouchOnMove(int oldPosition, int newPosition) {
        //DragDropUtil.onMove((ItemAdapter)itemAdapter, oldPosition, newPosition);  // change position
        return true;
    }

    @Override
    public void itemTouchDropped(int oldPosition, int newPosition) {
        //f.e. save new order in database
    }

    @Override
    public void itemSwiped(int position, int direction) {
        // -- Option 1: Direct action --
        //do something when swiped such as: select, remove, update, ...:
        //A) fastItemAdapter.select(position);
        //B) fastItemAdapter.remove(position);
        //C) update item, set "read" if an email etc

        // -- Option 2: Delayed action --
        final ModelItemView item = itemAdapter.getAdapterItem(position);
        item.setSwipedDirection(direction);

        // This can vary depending on direction but remove & archive simulated here both results in
        // removal from list
        final Runnable removeRunnable = new Runnable() {
            @Override
            public void run() {
                item.setSwipedAction(null);
                int position = itemAdapter.getAdapterPosition(item);
                if (position != RecyclerView.NO_POSITION) {
                    //this sample uses a filter. If a filter is used we should use the methods provided by the filter (to make sure filter and normal state is updated)
                    //fastItemAdapter.getItemFilter().remove(position);
                    itemAdapter.remove(position);
                }
            }
        };
        final View rv = oBinding.SongRecyclerView;
        rv.postDelayed(removeRunnable, 3000);

        item.setSwipedAction(new Runnable() {
            @Override
            public void run() {
                rv.removeCallbacks(removeRunnable);
                item.setSwipedDirection(0);
                int position = itemAdapter.getAdapterPosition(item);
                if (position != RecyclerView.NO_POSITION) {
                    fastAdapter.notifyItemChanged(position);
                }
            }
        });

        fastAdapter.notifyItemChanged(position);

        //TODO can this above be made more generic, along with the support in the item?
    }
}

这是可滑动的ModelItem(模型“ ModelSongCounter”只是一个POJO):

public class ModelItemView
        extends ModelAbstractItem<ModelSongCounter, ModelItemView, ModelItemView.ViewHolder>
        implements ISwipeable<ModelItemView, IItem>, IDraggable<ModelItemView, IItem> {

    public StringHolder undoTextSwipeFromLeft;
    public int iSwipedDirection;
    private Runnable rSwipedAction;
    public boolean bSwipable = true;
    public boolean draggable = true;

    public ModelItemView(ModelSongCounter icon) {
        super(icon);
    }

    /**
     * defines the type defining this item. must be unique. preferably an id
     *
     * @return the type
     */
    @Override
    public int getType() {
        return R.id.iconics_tag_id;
    }

    /**
     * defines the layout which will be used for this item in the list
     *
     * @return the layout for this item
     */
    @Override
    public int getLayoutRes() {
        return R.layout.item_view;
    }

    /**
     * binds the data of this item onto the viewHolder
     *
     * @param viewHolder the viewHolder of this item
     */
    @Override
    public void bindView(ViewHolder viewHolder, List<Object> payloads) {
        super.bindView(viewHolder, payloads);

        //define our data for the view
        viewHolder.name.setText(getModel().getName());
        viewHolder.counter.setText(Integer.toString(getModel().getCounter()));

        viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE);
        viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE);

        CharSequence swipedAction = null;
        CharSequence swipedText = null;
        if(iSwipedDirection != 0){
            swipedAction = viewHolder.itemView.getContext().getString(R.string.action_undo);
            swipedText = iSwipedDirection == ItemTouchHelper.LEFT ? "Removed" : "Archived - Should not be implemented!";
            viewHolder.swipeResultContent.setBackgroundColor(
                    ContextCompat.getColor(viewHolder.itemView.getContext(),
                    iSwipedDirection == ItemTouchHelper.LEFT ? R.color.md_red_900 : R.color.md_blue_900));
        }
        viewHolder.swipedAction.setText(swipedAction == null ? "" : swipedAction);
        viewHolder.swipedText.setText(swipedText == null ? "" : swipedText);
        viewHolder.rSwipedActionRunnable = this.rSwipedAction;
    }

    @Override
    public void unbindView(ViewHolder holder) {
        super.unbindView(holder);
        holder.name.setText(null);
        holder.counter.setText(null);
        holder.swipedAction.setText(null);
        holder.swipedText.setText(null);
        holder.rSwipedActionRunnable = this.rSwipedAction;
    }

    @Override
    public ViewHolder getViewHolder(View v) {
        return new ViewHolder(v);
    }

    //SWipable
    @Override
    public boolean isSwipeable() {
        return this.bSwipable;
    }

    @Override
    public ModelItemView withIsSwipeable(boolean swipeableP) {
        this.bSwipable = swipeableP;
        return this;
    }

    public void setSwipedDirection(int iSwipedDirectionP){
        this.iSwipedDirection = iSwipedDirectionP;
    }

    public void setSwipedAction(Runnable actionP){
        this.rSwipedAction = actionP;
    }

    @Override
    public boolean isDraggable() {
        return draggable;
    }

    @Override
    public ModelItemView withIsDraggable(boolean draggableP) {
        this.draggable = draggableP;
        return this;
    }

    /**
     * our ViewHolder
     */
    protected static class ViewHolder extends RecyclerView.ViewHolder {

        protected View view;

        @BindView(R.id.material_drawer_song)
        public TextView name;
        @BindView(R.id.material_drawer_counter)
        public TextView counter;
        @BindView(R.id.material_drawer_minus)
        public ImageView Minus;
        @BindView(R.id.material_drawer_plus)
        public ImageView Plus;

        @BindView(R.id.swipe_result_content)
        public View swipeResultContent;
        @BindView(R.id.item_content)
        public View itemContent;
        @BindView(R.id.swiped_text)
        public TextView swipedText;
        @BindView(R.id.swiped_action)
        public TextView swipedAction;

        public Runnable rSwipedActionRunnable;

        public ViewHolder(View view) {
            super(view);
            ButterKnife.bind(this, view);
            //this.view = view;// ?
            swipedAction.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (rSwipedActionRunnable != null){
                        rSwipedActionRunnable.run();
                    }
                }
            });
        }
    }
}

这是列表项的XML视图:

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

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="@dimen/material_drawer_item_primary">

    <LinearLayout
        android:id="@+id/swipe_result_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:visibility="visible"
        android:paddingEnd="@dimen/material_drawer_vertical_padding"
        android:paddingLeft="@dimen/material_drawer_vertical_padding"
        android:paddingRight="@dimen/material_drawer_vertical_padding"
        android:paddingStart="@dimen/material_drawer_vertical_padding">

        <TextView
            android:id="@+id/swiped_text"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:gravity="center_vertical|start"
            android:lines="1"
            android:singleLine="true"
            android:textDirection="anyRtl"
            android:textColor="@android:color/primary_text_dark"
            android:textSize="@dimen/material_drawer_item_primary_text"
            tools:text="Removed"/>
        <TextView
            android:id="@+id/swiped_action"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:fontFamily="sans-serif"
            android:gravity="center_vertical|start"
            android:lines="1"
            android:singleLine="true"
            android:textDirection="anyRtl"
            android:textAllCaps="true"
            android:textColor="@android:color/primary_text_dark"
            android:textStyle="bold"
            android:textSize="@dimen/material_drawer_item_primary_description"
            android:text="@string/action_undo"/>
    </LinearLayout>

    <LinearLayout
        android:id="@+id/item_content"
        android:layout_width="match_parent"
        android:layout_height="@dimen/material_drawer_item_primary"
        android:orientation="horizontal"
        android:paddingEnd="@dimen/material_drawer_vertical_padding"
        android:paddingLeft="@dimen/material_drawer_vertical_padding"
        android:paddingRight="@dimen/material_drawer_vertical_padding"
        android:paddingStart="@dimen/material_drawer_vertical_padding">

        <TextView
            android:id="@+id/material_drawer_song"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginTop="12dp"
            android:layout_marginLeft="12dp"
            android:lines="1"
            android:singleLine="true"
            android:textSize="@dimen/material_drawer_item_primary_text"
            tools:text="Some drawer text" />

        <TextView
            android:id="@+id/material_drawer_counter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp"
            android:layout_marginLeft="12dp"
            android:fontFamily="sans-serif"
            android:lines="1"
            android:singleLine="true"
            android:textSize="@dimen/material_drawer_item_primary_description"
            tools:text="Some counter text"


            android:layout_weight="1"
            android:gravity="center_vertical|start" />

        <ImageView
            android:id="@+id/material_drawer_minus"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            app:ico_color="@color/md_black_1000"
            app:ico_icon="@string/gmd_remove_circle"
            app:ico_size="50dp" />

        <ImageView
            android:id="@+id/material_drawer_plus"
            android:layout_width="50dp"
            android:layout_height="match_parent"
            app:ico_color="@color/md_black_1000"
            app:ico_icon="gmd-add_circle"
            app:ico_size="50dp" />
    </LinearLayout>

    </FrameLayout>
</layout>

2 个答案:

答案 0 :(得分:2)

管理undo按钮显示的代码部分位于bindView()的{​​{1}}方法内部。

请确保在刷卡后通过ModelItemView中的getItem(position)检索到正确的项目,并确保通过itemSwiped通知了正确的项目。

此后,确保再次在该元素上触发notifyItemChanged(),并确保它具有通过bindView()设置的正确swipeDirection

这很重要,因为:

setSwipedDirection(direction)

用于正确调整视图的可见性,包括显示viewHolder.swipeResultContent.setVisibility(iSwipedDirection != 0 ? View.VISIBLE : View.GONE); viewHolder.itemContent.setVisibility(iSwipedDirection != 0 ? View.GONE : View.VISIBLE); 按钮。

答案 1 :(得分:0)

几个星期后,答案很简单:

撤消按钮取决于itemanimator,为了避免闪烁,我总是将其取消。 Here是一个不错的自定义动画师类,它会覆盖不需要的任何动画。现在我要做的就是

RecyclerView.setItemAnimator(new CustomItemAnimator());