Я пытаюсь использовать swipeCallback в списке с modeladapter. Чтобы заставить это работать, я сократил все свои настройки и смоделировал их близко к образцу приложения, но комбинация выдает ошибку, не позволяющую отменить. Когда я провожу, это происходит:
Размах работает, но значок отмены не отображается. Есть идеи, что я делаю не так? Основной фрагмент таков:
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?
}
}
Это Swipable 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>