当RecyclerView中的项目出现时,我应该如何使它们动起来?
默认的项动画器仅在在设置了RecyclerView数据之后添加或删除数据时进行动画处理。
如何实现这一点?
当RecyclerView中的项目出现时,我应该如何使它们动起来?
默认的项动画器仅在在设置了RecyclerView数据之后添加或删除数据时进行动画处理。
如何实现这一点?
编辑:
该类定义在更改适配器时,项目上发生的动画。
因此,除非您将项目逐个添加到RecyclerView
并在每个迭代中刷新视图,否则我不认为ItemAnimator
是满足您需求的解决方案。
以下是使用CustomAdapter在项目出现时如何对RecyclerView
项目执行动画的方法:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder>
{
private Context context;
// The items to display in your RecyclerView
private ArrayList<String> items;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public static class ViewHolder extends RecyclerView.ViewHolder
{
TextView text;
// You need to retrieve the container (ie the root ViewGroup from your custom_item_layout)
// It's the view that will be animated
FrameLayout container;
public ViewHolder(View itemView)
{
super(itemView);
container = (FrameLayout) itemView.findViewById(R.id.item_layout_container);
text = (TextView) itemView.findViewById(R.id.item_layout_text);
}
}
public CustomAdapter(ArrayList<String> items, Context context)
{
this.items = items;
this.context = context;
}
@Override
public CustomAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.custom_item_layout, parent, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position)
{
holder.text.setText(items.get(position));
// Here you apply the animation when the view is bound
setAnimation(holder.itemView, position);
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position)
{
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition)
{
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
:
<FrameLayout
android:id="@+id/item_layout_container"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/item_layout_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"/>
</FrameLayout>
有关CustomAdapters和RecyclerView
的更多信息,请参阅官方文档中的培训。
快速滚动问题
使用此方法可能会导致快速滚动时出现问题。当动画正在进行时,视图可能会被重用。为了避免这种情况,建议在分离时清除动画。
@Override
public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder)
{
((CustomViewHolder)holder).clearAnimation();
}
关于CustomViewHolder:
public void clearAnimation()
{
mRootLayout.clearAnimation();
}
新回答:
看一下Gabriele Mariotti的仓库,我相信你会找到所需的内容。他为RecyclerView提供了简单的ItemAnimators,例如SlideInItemAnimator或SlideScaleItemAnimator。
仅使用XML的简单制作
res/anim/layout_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_animation_fall_down"
android:animationOrder="normal"
android:delay="15%" />
res/anim/item_animation_fall_down.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="500">
<translate
android:fromYDelta="-20%"
android:toYDelta="0"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:interpolator="@android:anim/decelerate_interpolator"
/>
<scale
android:fromXScale="105%"
android:fromYScale="105%"
android:toXScale="100%"
android:toYScale="100%"
android:pivotX="50%"
android:pivotY="50%"
android:interpolator="@android:anim/decelerate_interpolator"
/>
</set>
在布局和RecyclerView中使用:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/layout_animation"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
recyclerView.scheduleLayoutAnimation()
,动画将无法正常工作。请注意不要改变原本的意思,让翻译更易懂。 - zeleven我在下面的代码中实现了当Recyclerview
的项首次出现时淡入动画。也许对某些人有用。
private final static int FADE_DURATION = 1000; //FADE_DURATION in milliseconds
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// Set the view to fade in
setFadeAnimation(holder.itemView);
}
private void setFadeAnimation(View view) {
AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
你也可以使用以下的 setScaleAnimation()
替换 setFadeAnimation()
,通过缩放动画从一个点开始来实现物品的出现动画:
private void setScaleAnimation(View view) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(FADE_DURATION);
view.startAnimation(anim);
}
以上代码存在一些缺陷,因为当你滚动 RecyclerView
时,项目会经常淡入淡出或缩放。如果你愿意,可以添加代码以仅在包含 RecyclerView
的片段或活动首次创建时允许动画发生(例如,在创建时获取系统时间,并仅允许前 FADE_DURATION
毫秒进行动画)。
我根据pbm的回答创建了一个动画,只进行了少量的修改
,使得动画仅运行一次。
换句话说,滚动到页面后才会出现该动画
。
private int lastPosition = -1;
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it's animated
if (position > lastPosition) {
ScaleAnimation anim = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
anim.setDuration(new Random().nextInt(501));//to make duration random number between [0,501)
viewToAnimate.startAnimation(anim);
lastPosition = position;
}
}
onBindViewHolder
中调用该函数。@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.getTextView().setText("some text");
// call Animation function
setAnimation(holder.itemView, position);
}
lastPosition
表示已渲染视图的数量,因此在开始时它的值为 -1
,每次渲染新视图时我们都会启动动画并增加位置。 - Basheer AL-MOMANI您可以像这样为RecyclerView
添加一个android:layoutAnimation="@anim/rv_item_animation"
属性:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_animation_fall_down"
/>
你甚至不需要整个库,那个类就足够了。 然后,如果你实现了一个自己的适配器类,并像这样提供一个动画:
@Override
protected Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}
@Override
public long getItemId(final int position) {
return getWrappedAdapter().getItemId(position);
}
当滚动时,您将看到项目从底部出现,并避免快速滚动所带来的问题。
private void setZoomInAnimation(View view) {
Animation zoomIn = AnimationUtils.loadAnimation(context, R.anim.zoomin);// animation file
view.startAnimation(zoomIn);
}
setZoomInAnimation(holder.itemView);
http://frogermcs.github.io/Instagram-with-Material-Design-concept-is-getting-real/
但是,如果链接失效,我会复制并粘贴代码。if (savedInstanceState == null) {
pendingIntroAnimation = true;
}
步骤2:您需要将此代码放入您想要开始动画的方法中:
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
inboxMenuItem = menu.findItem(R.id.action_inbox);
inboxMenuItem.setActionView(R.layout.menu_item_view);
if (pendingIntroAnimation) {
pendingIntroAnimation = false;
startIntroAnimation();
}
return true;
}
步骤 3:现在编写 startIntroAnimation() 的逻辑:
private static final int ANIM_DURATION_TOOLBAR = 300;
private void startIntroAnimation() {
btnCreate.setTranslationY(2 * getResources().getDimensionPixelOffset(R.dimen.btn_fab_size));
int actionbarSize = Utils.dpToPx(56);
toolbar.setTranslationY(-actionbarSize);
ivLogo.setTranslationY(-actionbarSize);
inboxMenuItem.getActionView().setTranslationY(-actionbarSize);
toolbar.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(300);
ivLogo.animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(400);
inboxMenuItem.getActionView().animate()
.translationY(0)
.setDuration(ANIM_DURATION_TOOLBAR)
.setStartDelay(500)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
startContentAnimation();
}
})
.start();
}
我的首选方案:
我更倾向于对整个recyclerview进行动画处理,而不是对其中的项进行动画处理。
步骤1和2保持不变。
在步骤3中,一旦API调用返回数据,我将立即开始动画处理。
private void startIntroAnimation() {
recyclerview.setTranslationY(latestPostRecyclerview.getHeight());
recyclerview.setAlpha(0f);
recyclerview.animate()
.translationY(0)
.setDuration(400)
.alpha(1f)
.setInterpolator(new AccelerateDecelerateInterpolator())
.start();
}
latestPostRecyclerview
是什么? - Antonio2019年,我建议将所有的项目动画放入ItemAnimator中。
让我们从在recycler-view中声明动画开始:
with(view.recycler_view) {
adapter = Adapter()
itemAnimator = CustomAnimator()
}
class CustomAnimator() : DefaultItemAnimator() {
override fun animateAppearance(
holder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo?,
postInfo: ItemHolderInfo): Boolean{} // declare what happens when a item appears on the recycler view
override fun animatePersistence(
holder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo,
postInfo: ItemHolderInfo): Boolean {} // declare animation for items that persist in a recycler view even when the items change
}
类似上面的动画,有消失动画animateDisappearance
,添加动画animateAdd
,改变动画animateChange
和移动动画animateMove
。
一个重要的点是在其中调用正确的动画派发器。
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
setBindAnimation(holder)
}
如果您想在RV中查看每个附加动画。
onViewDetachedFromWindow
方法,并在视图上调用clearAnimation
。问题在于当RecyclerView尝试重用视图时,可能会有正在运行的动画。 - XampleonViewDetachedFromWindow
。 - Xample