2014-11-28 21 views
42

Tôi đang sử dụng RecyclerView lần đầu tiên. Mọi thứ đều hoạt động tốt ngoại trừ việc không có hoạt ảnh nào khi xóa mục mặc dù hoạt ảnh trên mục bổ sung chỉ hoạt động tốt.Không hoạt ảnh khi xóa mục trên RecyclerView

tôi đã không đặt bất kỳ phim hoạt hình mục tùy chỉnh, nhưng theo documentation:

Animations để thêm và xóa các mặt hàng đã được kích hoạt theo mặc định trong RecyclerView.

Vì vậy, hoạt ảnh khi xóa sẽ hoạt động.

Tôi muốn có hoạt ảnh mặc định khi xóa nhưng không thể làm việc đó.

Đây là cách tôi thiết lập các RecyclerView:

private void setupRecyclerView() { 
    mRecyclerView = (RecyclerView) mRootView.findViewById(R.id.recycler_view); 
    mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 
    View emptyView = mRootView.findViewById(R.id.empty_view); 
    mAdapter = new RoutineAdapter(getActivity(), mRoutineItems, emptyView); 
    mRecyclerView.setAdapter(mAdapter); 
} 

Đây là bộ chuyển đổi của tôi:

private class RoutineAdapter 
     extends RecyclerView.Adapter<RoutineAdapter.ViewHolder> { 

private final Context mContext; 
private List<RoutineItem> mData; 
private View mEmptyView; 

    public RoutineAdapter(Context context, List<RoutineItem> data, View emptyView) { 
     mContext = context; 
     mData = data; 
     mEmptyView = emptyView; 
     setEmptyViewVisibility(); 
    } 

    public void add(RoutineItem routineItem, int position) { 
     mData.add(position, routineItem); 
     setEmptyViewVisibility(); 
     notifyItemInserted(position); 
    } 

    public void remove(int position){ 
     mData.remove(position); 
     setEmptyViewVisibility(); 
     notifyItemRemoved(position); 
    } 

    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     final View view = LayoutInflater.from(mContext).inflate(
      R.layout.fragment_routines_list_item, parent, false); 
     return new ViewHolder(view); 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, final int position) { 
     final RoutineItem routineItem = getItem(position); 
     holder.circle.setBackgroundResource(
      colorNumberToDrawableResource(routineItem.colorNumber)); 
     holder.initial.setText(routineItem.routineName.substring(0, 1)); 
     holder.routineName.setText(routineItem.routineName); 
     holder.lastTimeDone.setText(routineItem.lastTimeDoneText); 
     if (routineItem.isSelected) { 
     holder.itemView.setBackgroundColor(
      getResources().getColor(R.color.background_item_selected)); 
     } else { 
     holder.itemView.setBackgroundResource(
      R.drawable.darker_background_on_pressed); 
     } 
     holder.itemView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      mPresenter.onRoutineClicked(routineItem.routineName); 
     } 
     }); 
     holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
      mPresenter.onRoutineLongClicked(routineItem.routineName); 
      return true; 
     } 
     }); 
    } 

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

    public RoutineItem getItem(int position) { 
     return mData.get(position); 
    } 

    private void setEmptyViewVisibility() { 
     if (getItemCount() == 0) { 
     mEmptyView.setVisibility(View.VISIBLE); 
     } else { 
     mEmptyView.setVisibility(View.GONE); 
     } 
    } 

    class ViewHolder extends RecyclerView.ViewHolder { 
     public final View circle; 
     public final TextView initial; 
     public final TextView routineName; 
     public final TextView lastTimeDone; 

     public ViewHolder(View view) { 
     super(view); 
     circle = view.findViewById(R.id.circle); 
     initial = (TextView) view.findViewById(R.id.initial); 
     routineName = (TextView) view.findViewById(R.id.routine_name); 
     lastTimeDone = (TextView) view.findViewById(R.id.last_time_done); 
     } 
    } 
} 

Fragment_routines_list_item.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:minHeight="@dimen/standard_list_item_height" 
    android:paddingBottom="8dp" 
    android:background="@drawable/darker_background_on_pressed" 
    android:clickable="true"> 
    ...... 
</RelativeLayout> 

Tôi đang làm gì sai gây ra hoạt ảnh xóa mặc định không hoạt động?

Trả lời

31

Giải quyết.

Vấn đề là sau khi gọi mAdapter.remove(position), một phần khác của mã của tôi đã gọi số mAdapter.notifyDataSetChanged() mà tôi giả định dừng hoạt ảnh xóa.

Để tổng hợp, nếu bạn gọi mAdapter.notifyDataSetChanged trong khi có hoạt ảnh liên tục, hoạt ảnh sẽ dừng.

+9

Và chỉ số sẽ được điều sai lầm nếu bạn không. – milosmns

+0

sau đó làm cách nào để khắc phục? – MobileMon

+3

Giải pháp khắc phục sự cố này là sử dụng viewHolder.getAdapterPosition() cho onClick thay vì vị trí được chuyển vào bên trong của onBindViewHolder – MobileMon

-1

Tôi chạy vào cùng một vấn đề, và tôi cố định này bằng cách thực hiện RecyclerView của riêng tôi, và trong recyclerview của tôi, tôi đã làm điều này:

public class MyRecyclerView extends RecyclerView { 
    private View mEmptyView; 
    private AdapterDataObserver mDataObserver = new AdapterDataObserver() { 
     public void onChanged() { 
      super.onChanged(); 
      updateEmptyView(); 
     } 

     public void onItemRangeRemoved(int positionStart, int itemCount) { 
      super.onItemRangeRemoved(positionStart, itemCount); 
      updateEmptyView(); 
     } 

     public void onItemRangeInserted(int positionStart, int itemCount) { 
      super.onItemRangeInserted(positionStart, itemCount); 
      updateEmptyView(); 
     } 
    }; 

    // private void setAdapter() {} 

    private void updateEmptyView() { 
     // update empty view's visibility 
    } 

} 

Về cơ bản, khi bạn thêm/gỡ bỏ các mục vào/từ recyclerview, bạn có thể gọi notifyItemInserted()/notifyItemRemoved() và notifyItemRangeChanged(), phương thức này sẽ gọi onItemRangeRemoved()/onItemRangeInserted() trong mDataObserver. Vì vậy, trong phương pháp này, bạn có thể cập nhật chế độ hiển thị của chế độ xem trống và sẽ không làm hỏng hoạt ảnh.

43

Cách thích hợp để loại bỏ một mục từ quan điểm tái chế là để loại bỏ các mục từ tập dữ liệu và sau đó nói với adapter rằng mục được lấy ra như vậy

myDataset.remove(position); // myDataset is List<MyObject> 
mAdapter.notifyItemRemoved(position); 
+2

nhờ người đàn ông này làm việc cho tôi – commonSenseCode

3

tôi đã có thể loại bỏ quan điểm với hình ảnh động và các chỉ số được cập nhật như sau:

trong vòng adapter,

public boolean removeItem(int position) { 
    if (data.size() >= position + 1) { 
     data.remove(position); 
     return true; 
    } 
    return false; 
} 

trong khi loại bỏ các quan điểm, hãy gọi

if (adapter.removeItem(position)) { 
    adapter.notifyItemRemoved(position); 
    adapter.notifyItemRangeChanged(position, adapter.getItemCount()); 
} 

Tôi đã sử dụng phương pháp boolean để đảm bảo rằng nhấp đúp, v.v. không gây tai nạn.

6

Sử dụng notifyItemRemoved(position) thay vì notifyDataSetChanged() như dưới đây

myDataset.remove(position); 
notifyItemRemoved(position); 

notifyDataSetChanged() chỉ đơn giản là thông báo cho các dữ liệu được cập nhật mà không cần bất kỳ hình ảnh động.

5

Một lý do khác cho hoạt động xóa hoạt động không đúng cách có thể là chiều cao RecyclerViews. Xác minh rằng chiều cao là match_parent và KHÔNG wrap_content!

+1

Đó là một lý do khác. Hoạt ảnh chèn hoạt động với 'wrap_content' nhưng không hoạt động với thao tác xóa. Bất kỳ cách nào để giải quyết vấn đề này? –

2

sau khi gỡ lỗi lâu tôi nhận ra tôi đã có thêm setHasStableIds(true) đến bộ chuyển đổi của tôi và thực hiện

@Override 
public long getItemId(int position) { 
    return position; 
} 

sau đó loại bỏ hình ảnh động bắt đầu làm việc

Các vấn đề liên quan