如何在我的回收站视图项目中依次添加动画幻灯片。就像活动开始一样,回收者视图的列表项逐个滑动。我正在使用LinearLayoutManager
不是所有人都应该同时滑入。甚至在滚动时也是如此。就在创建活动时。
我搜索但没有找到任何东西。
我希望实现这样的目标:https://youtu.be/Q8TXgCzxEnw?t=30s
答案 0 :(得分:1)
我在几个月前整理了一个示例应用程序,它在重新洗牌期间有一个顺序幻灯片插入动画。我们提供了演示视频here。它应该给你一些想法。
指向最相关的类文件的链接是here,我将复制下面的代码。
public class AllNotesFragmentRecyclerView extends RecyclerView {
private static final int BASE_ANIMATION_TIME = 50;
private static final int MAX_ANIMATION_TIME_INCREMENT = 100;
private int screenWidth;
private int startX, finalX;
private int[] interpolatedAnimationTimes;
public AllNotesFragmentRecyclerView(Context context) {
super(context);
init(context);
}
public AllNotesFragmentRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AllNotesFragmentRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
calculateScreenWidth(context);
startX = 0;
finalX = -(screenWidth);
}
private void calculateScreenWidth(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
}
private int calculateInterpolatedAnimationTime(int currentIndex, int maxIndex) {
float percentage = ((float)currentIndex/(float)maxIndex);
float increment = (float) MAX_ANIMATION_TIME_INCREMENT * percentage;
return (int) (BASE_ANIMATION_TIME + increment);
}
public void updateListOrder() {
createAnimatorSet();
}
private void createAnimatorSet() {
AnimatorSet set = new AnimatorSet();
ArrayList<Animator> animArrayList = new ArrayList<>();
for (int i = 0; i < getChildCount(); i++) {
ObjectAnimator anim = ObjectAnimator
.ofFloat(getChildAt(i), "translationX", finalX);
int duration = calculateInterpolatedAnimationTime(i, getChildCount());
anim.setDuration(duration);
anim.addListener(new RowAnimationListener(i, duration, startX));
animArrayList.add(anim);
}
set.setInterpolator(new AccelerateInterpolator());
set.playSequentially(animArrayList);
set.start();
}
private void animateOn(int childPosition, int duration, int targetValue) {
ObjectAnimator animator = ObjectAnimator
.ofFloat(getChildAt(childPosition), "translationX", targetValue);
animator.setInterpolator(new DecelerateInterpolator());
animator.setDuration(duration);
animator.start();
}
//...
private class RowAnimationListener implements Animator.AnimatorListener {
private int position, duration, targetX;
public RowAnimationListener(int position, int duration, int targetX) {
this.position = position;
this.duration = duration;
this.targetX = targetX;
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
int currentItem = getLinearLayoutManager().findFirstVisibleItemPosition() + position;
getAdapter().notifyItemChanged(currentItem);
notifyRowsPeripheralToVisibleItemsDataChanged(position);
animateOn(position, duration, targetX);
}
@Override
public void onAnimationCancel(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
}
}
答案 1 :(得分:1)
最后我找到了解决方案。在下面的代码片段中,我将解释如何实现。它很简单,可以在任何现有工作RecyclerView
上完成。我在评论中解释了一切。
这是onCreate
/ onCreateView
方法(我在Fragment中使用了这个,你可以根据需要进行相应更改):
RecyclerView recList = (RecyclerView) rootView.findViewById(R.id.event_list);
recList.setHasFixedSize(true);
LinearLayoutmanager llm = new LinearLayoutManager(getActivity().getApplicationContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
// This is important. Setting recyclerView's alpha to zero.
// Basically this is just to hide recyclerview at start before binding data
// As setVisibility is not working on recycler view object.
recList.setAlpha(0);
// Create the EventAdapter with the result we got
// EventAdapter is my custom adapter class.
// you should set your adapter class
EventAdapter ea = new EventAdapter(eventResultList);
// Binding the Adapter to RecyclerView list to show the data
recList.setAdapter(ea);
// ********************* Animate at start ********************************
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
// This will give me the initial first and last visible element's position.
// This is required as only this elements needs to be animated
// Start will be always zero in this case as we are calling in onCreate
int start = llm.findFirstVisibleItemPosition();
int end = llm.findLastVisibleItemPosition();
Log.i("Start: ", start + "");
Log.i("End: ", end + "");
// Multiplication factor
int DELAY = 50;
// Loop through all visible element
for (int i = start; i <= end; i++) {
Log.i("Animatining: ", i + "");
// Get View
View v = recList.findViewHolderForAdapterPosition(i).itemView;
// Hide that view initially
v.setAlpha(0);
// Setting animations: slide and alpha 0 to 1
PropertyValuesHolder slide = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, 150, 0);
PropertyValuesHolder alpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0, 1);
ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(v, slide, alpha);
a.setDuration(300);
// It will set delay. As loop progress it will increment
// And it will look like items are appearing one by one.
// Not all at a time
a.setStartDelay(i * DELAY);
a.setInterpolator(new DecelerateInterpolator());
a.start();
}
// Set Recycler View visible as all visible are now hidden
// Animation will start, so set it visible
recList.setAlpha(1);
}
}, 50);
这是一个没有评论的相当小的代码。
有些事情需要解释:
为什么最初隐藏RecyclerView?
如果最初未隐藏RecyclerView
,您会在动画开始前注意到闪烁。原因是当你设置数据适配器时,它会将它定位在默认位置,并在循环后开始动画。因此,在while循环运行之间,您会注意到RecyclerView
中的突然闪烁,它们最初都位于其初始位置,而不是突然动画。
首先隐藏它,然后完成循环,并且所有可见位置动画都设置为延迟并开始,我们可以显示RecyclerView
。它使滑动看起来很光滑。
使用setAlpha(0)
隐藏它的原因是setVisibility()
函数无效RecyclerView
对象。
只有可见元素才能生成动画?
LayoutManager
类中有一些函数可以获取可见元素的位置。在LinearLayoutManager
中使用findFirstVisibleItemPosition()
从屏幕上可见的回收者视图数据中获取第一个可见视图的位置。可以使用findLastVisibleItemPosition()
重试最后一个可见视图的位置。因此,我们可以从第一个视图循环到最后一个视图,并为开始时将在屏幕上显示的初始视图设置动画。
延迟有效吗?
由于循环将从0
(开始)进展到end
,它将设置延迟从0,50,100,150,...如果DELAY
变量设置为50.所以这将首先元素开始动画,第二次延迟50ms后,第三次延迟100ms后依此类推。所以看起来他们会一个接一个地进入。不是全部在一起。
答案 2 :(得分:1)
在anim/slide_in.xml
文件中创建动画,如下所示
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="@android:anim/decelerate_interpolator">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="2000"/>
</set>
然后在onBindViewHolder
方法中的RecyclerView的每个视图上应用此动画。
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ViewHolder vh = (ViewHolder) holder;
vh1.tv_header.setText(mList.get(position));
Animation animation = AnimationUtils.loadAnimation(mContext,R.anim.rec_anim);
animation.setStartOffset(30 * position);//Provide delay here
holder.itemView.startAnimation(animation);
}