我正在使用RecyclerView
,新项目只显示在列表顶部。我想对此操作使用默认插入动画,但它会在OnClick()
内打破ViewHolder
方法
如果我插入了新项,OnClick()
将使用前一项ArrayList中的数据。如果我使用NotifyDataSetChanged()
,数据是可以的,但当然,没有动画。看起来没有调用ViewHolder.bind()
方法存在问题。如何在NotifyItemInserted(0)
之后更新每个项目的索引?
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private Context context;
private LayoutInflater inflater;
private ArrayList<Song> data = new ArrayList<>();
//то, что ниже - для анимации
private static final int UNSELECTED = -1;
private RecyclerView recyclerView;
private int selectedItem = UNSELECTED;
public RecyclerAdapter(Context context, ArrayList<Song> data, RecyclerView recyclerView) {
this.context = context;
inflater = LayoutInflater.from(context);
this.data = data;
this.recyclerView = recyclerView;
}
public void insert(Song song)
{
data.add(0, song);
recyclerView.scrollToPosition(0);
notifyItemInserted(0);
}
public void swap(ArrayList<Song> datas){
data.clear();
data.addAll(datas);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView tv_songName;
TextView tv_songGenreID;
TextView tv_songUserInfo;
ExpandableLayout expandableLayout;
private CardView expandButton;
private int position;
private TextView youtubeButton;
private TextView shareButton;
public ViewHolder(View itemView) {
super(itemView);
tv_songName = (TextView) itemView.findViewById(R.id.tv_songName);
tv_songGenreID = (TextView) itemView.findViewById(R.id.tv_songGenreID);
tv_songUserInfo = (TextView) itemView.findViewById(R.id.tv_songUserInfo);
youtubeButton = (TextView) itemView.findViewById(R.id.youtube_button);
shareButton = (TextView) itemView.findViewById(R.id.share_button);
expandableLayout = (ExpandableLayout) itemView.findViewById(R.id.expandable_layout);
expandableLayout.setInterpolator(new OvershootInterpolator());
expandButton = (CardView) itemView.findViewById(R.id.card_view);
expandButton.setOnClickListener(this);
youtubeButton.setOnClickListener(this);
shareButton.setOnClickListener(this);
}
public void bind(int position) {
this.position = position;
Song current = data.get(position);
StringBuilder songInfo = new StringBuilder();
songInfo.append(context.getString(R.string.genre));
songInfo.append(current.songGenreID);
songInfo.append(System.getProperty("line.separator"));
songInfo.append(context.getString(R.string.album));
this.tv_songName.setText(current.songName);
this.tv_songGenreID.setText(songInfo);
this.tv_songUserInfo.setText(current.songUserInfo);
expandButton.setSelected(false);
expandableLayout.collapse(false);
}
@Override
public void onClick(View view) {
switch (view.getId())
{
case R.id.youtube_button:
String youtubeURL = data.get(position).songName.replaceAll(" ", "%20");
youtubeURL = "https://www.youtube.com/results?search_query=" + youtubeURL;
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(youtubeURL));
context.startActivity(browserIntent);
break;
case R.id.share_button:
String songName = data.get(position).songName;
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_TEXT, songName);
shareIntent.setType("text/plain");
context.startActivity(shareIntent);
break;
default:
ViewHolder holder = (ViewHolder) recyclerView.findViewHolderForAdapterPosition(selectedItem);
if (holder != null) {
holder.expandButton.setSelected(false);
holder.expandableLayout.collapse();
}
if (position == selectedItem) {
selectedItem = UNSELECTED;
} else {
expandButton.setSelected(true);
expandableLayout.expand();
selectedItem = position;
}
break;
}
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v=inflater.inflate(R.layout.recycler_item, parent,false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(position);
setAnimation(holder.itemView, position);
}
private int lastPosition = -1;
private void setAnimation(View viewToAnimate, int position) {
if (position > lastPosition) {
Animation anim = AnimationUtils.loadAnimation(context, android.R.anim.fade_in);
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
@Override
public int getItemCount() {
return data.size();
}
}
Activity.java的OnCreate()
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme_NoActionBar);
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
layout = (CoordinatorLayout)findViewById(R.id.coordinator1);
FloatingActionButton myFab = (FloatingActionButton) findViewById(R.id.floatingActionButton);
mRecyclerView = (RecyclerViewEmptySupport) findViewById(R.id.my_recycler_view);
mRecyclerView.setEmptyView(findViewById(R.id.list_empty));
myFab.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getSupportFragmentManager();
AddSongDialogFragment addSongDialogFragment = new AddSongDialogFragment();
addSongDialogFragment.show(fm, "add_song");
}
});
mAdapter = new RecyclerAdapter(MainActivity.this, data, mRecyclerView);
mLayoutManager = new LinearLayoutManager(MainActivity.this);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(mLayoutManager);
dbHelper = new DBHelper(this);
mAdapter.swap(dbHelper.readFromDB());
RecyclerView.ItemAnimator itemAnimator = new DefaultItemAnimator();
itemAnimator.setAddDuration(700);
itemAnimator.setRemoveDuration(1000);
mRecyclerView.setItemAnimator(itemAnimator);
}
答案 0 :(得分:2)
使用getAdapterPosition()从您的VIewHolder获取商品的正确位置。这样,在从RecyclerView移动/删除项目后,位置不会混淆。
注意:如果用户在动画期间点击空白区域getAdapterPosition()
可能会返回-1:请确保处理该案例。
答案 1 :(得分:1)
添加新项目后,您可以使用notifyItemRangeChanged(position, data.size());
通知其他项目。
如果您使用swap()
notifyItemRemoved()
和notifyItemInserted()
而非notifyItemMoved()
功能,也可以为notifyDataSetChanged()
功能设置动画。您只需要检查新列表是否包含旧列表的项目。