FastAdapter: Undo button does not show up after swipe












0















I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:



enter image description here



The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:



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?
}
}


This is the swipable ModelItem (the model "ModelSongCounter" is just a 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();
}
}
});
}
}
}


And this is the XML-view of the List-Item:



<?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>









share|improve this question





























    0















    I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:



    enter image description here



    The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:



    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?
    }
    }


    This is the swipable ModelItem (the model "ModelSongCounter" is just a 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();
    }
    }
    });
    }
    }
    }


    And this is the XML-view of the List-Item:



    <?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>









    share|improve this question



























      0












      0








      0








      I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:



      enter image description here



      The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:



      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?
      }
      }


      This is the swipable ModelItem (the model "ModelSongCounter" is just a 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();
      }
      }
      });
      }
      }
      }


      And this is the XML-view of the List-Item:



      <?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>









      share|improve this question
















      I am trying to use a swipeCallback on a list with modeladapter. In order to make it work, I stripped down all my customization and modeled it close to the sample app, but the combination produces the error of not allowing undo. When I swipe, this happens:



      enter image description here



      The swipe works, but the undo icon does not show up. Any ideas what I am doing wrong? The underlying fragment is this:



      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?
      }
      }


      This is the swipable ModelItem (the model "ModelSongCounter" is just a 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();
      }
      }
      });
      }
      }
      }


      And this is the XML-view of the List-Item:



      <?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>






      android android-recyclerview swipe fastadapter






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 '18 at 20:25









      mikepenz

      8,605859103




      8,605859103










      asked Nov 2 '18 at 23:57









      Apfelsaft23Apfelsaft23

      68111




      68111
























          2 Answers
          2






          active

          oldest

          votes


















          2














          The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.



          Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().



          After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).



          This is important as:



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


          Is used to properly adjust the visibility of the views, including showing the undo button.






          share|improve this answer































            0














            After several weeks, the answer is simple:



            The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was



            RecyclerView.setItemAnimator(new CustomItemAnimator());





            share|improve this answer
























            • Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

              – mikepenz
              Nov 24 '18 at 11:20











            • Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

              – Apfelsaft23
              Nov 28 '18 at 15:54













            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53127139%2ffastadapter-undo-button-does-not-show-up-after-swipe%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            2














            The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.



            Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().



            After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).



            This is important as:



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


            Is used to properly adjust the visibility of the views, including showing the undo button.






            share|improve this answer




























              2














              The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.



              Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().



              After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).



              This is important as:



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


              Is used to properly adjust the visibility of the views, including showing the undo button.






              share|improve this answer


























                2












                2








                2







                The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.



                Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().



                After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).



                This is important as:



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


                Is used to properly adjust the visibility of the views, including showing the undo button.






                share|improve this answer













                The part of the code managing the display of the undo button is inside the bindView() method of the ModelItemView.



                Please ensure that after swiping the correct item is retrieved via the getItem(position) in the itemSwiped and ensure that the correct item gets notified via notifyItemChanged().



                After that ensure that the bindView() is triggered again on that element, and that it has the proper swipeDirection as set via setSwipedDirection(direction).



                This is important as:



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


                Is used to properly adjust the visibility of the views, including showing the undo button.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 23 '18 at 20:23









                mikepenzmikepenz

                8,605859103




                8,605859103

























                    0














                    After several weeks, the answer is simple:



                    The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was



                    RecyclerView.setItemAnimator(new CustomItemAnimator());





                    share|improve this answer
























                    • Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                      – mikepenz
                      Nov 24 '18 at 11:20











                    • Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                      – Apfelsaft23
                      Nov 28 '18 at 15:54


















                    0














                    After several weeks, the answer is simple:



                    The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was



                    RecyclerView.setItemAnimator(new CustomItemAnimator());





                    share|improve this answer
























                    • Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                      – mikepenz
                      Nov 24 '18 at 11:20











                    • Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                      – Apfelsaft23
                      Nov 28 '18 at 15:54
















                    0












                    0








                    0







                    After several weeks, the answer is simple:



                    The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was



                    RecyclerView.setItemAnimator(new CustomItemAnimator());





                    share|improve this answer













                    After several weeks, the answer is simple:



                    The undo-Button depends on the itemanimator which I always nullified to avoid the blinking. Here is a nice custom animator class that supresses whatever animation you dont want. Now all I had to do was



                    RecyclerView.setItemAnimator(new CustomItemAnimator());






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Nov 24 '18 at 0:25









                    Apfelsaft23Apfelsaft23

                    68111




                    68111













                    • Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                      – mikepenz
                      Nov 24 '18 at 11:20











                    • Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                      – Apfelsaft23
                      Nov 28 '18 at 15:54





















                    • Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                      – mikepenz
                      Nov 24 '18 at 11:20











                    • Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                      – Apfelsaft23
                      Nov 28 '18 at 15:54



















                    Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                    – mikepenz
                    Nov 24 '18 at 11:20





                    Funny enough that should not be necessary. Did you debug and see if the notify would correctly trigger the update of the item via its bindView()?

                    – mikepenz
                    Nov 24 '18 at 11:20













                    Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                    – Apfelsaft23
                    Nov 28 '18 at 15:54







                    Hi Mike! Yes, the bindview stuff ist triggered. I also tested it with your sample app - when I nullify the animator, the undo button wont show up. From what I can tell, the Undo Swipe definitely depends on an itemAnimator.

                    – Apfelsaft23
                    Nov 28 '18 at 15:54




















                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53127139%2ffastadapter-undo-button-does-not-show-up-after-swipe%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Lallio

                    Unable to find Lightning Node

                    Futebolista