我正在尝试实现自己的RecyclerView动画 - 我想在不使用任何外部库的情况下实现这一点。以下是理论动画应该看起来像什么。
用户单击列表中的项目,接着发生一个动画,打开另一个视图。
从高层次上来看,可能只需要伪代码和最少的代码,怎样才能创建像那样的动画呢?
此外,如果用户点击相同的项或其他项,动画也应该能够反向进行
我并不非常熟悉RecyclerView类,并希望了解更多关于它以及与其相关的任何动画的知识。
我正在尝试实现自己的RecyclerView动画 - 我想在不使用任何外部库的情况下实现这一点。以下是理论动画应该看起来像什么。
用户单击列表中的项目,接着发生一个动画,打开另一个视图。
从高层次上来看,可能只需要伪代码和最少的代码,怎样才能创建像那样的动画呢?
此外,如果用户点击相同的项或其他项,动画也应该能够反向进行
我并不非常熟悉RecyclerView类,并希望了解更多关于它以及与其相关的任何动画的知识。
解决方案:
我解决这个问题的方法是在ViewHolder
类中实现一个监听器View.OnClickListener
,该类extends RecyclerView.ViewHolder
。因此,我们得到以下代码:
public static class ExampleViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
private int originalHeight = 0;
private boolean isViewExpanded = false;
private YourCustomView yourCustomView
// ..... CODE ..... //
}
变量originalHeight
和isViewExpanded
被用于动画过程中。在构造函数中,我将视图初始化为View.OnClickListener
,如下所示:
public ExampleViewHolder(View v) {
super(v);
v.setOnClickListener(this);
// Initialize other views, like TextView, ImageView, etc. here
// If isViewExpanded == false then set the visibility
// of whatever will be in the expanded to GONE
if (isViewExpanded == false) {
// Set Views to View.GONE and .setEnabled(false)
yourCustomView.setVisibility(View.GONE);
yourCustomView.setEnabled(false);
}
}
现在构造函数已经处理完毕,我们想要配置当用户单击单个RecyclerView
项时发生的情况。在这里将有用的类是ValueAnimator
和Animation
对象。我们通过覆盖onClick
方法来实现这一点:
@Override
public void onClick(final View view) {
// If the originalHeight is 0 then find the height of the View being used
// This would be the height of the cardview
if (originalHeight == 0) {
originalHeight = view.getHeight();
}
// Declare a ValueAnimator object
ValueAnimator valueAnimator;
if (!mIsViewExpanded) {
yourCustomView.setVisibility(View.VISIBLE);
yourCustomView.setEnabled(true);
mIsViewExpanded = true;
valueAnimator = ValueAnimator.ofInt(originalHeight, originalHeight + (int) (originalHeight * 2.0)); // These values in this method can be changed to expand however much you like
} else {
mIsViewExpanded = false;
valueAnimator = ValueAnimator.ofInt(originalHeight + (int) (originalHeight * 2.0), originalHeight);
Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out
a.setDuration(200);
// Set a listener to the animation and configure onAnimationEnd
a.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
yourCustomView.setVisibility(View.INVISIBLE);
yourCustomView.setEnabled(false);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
// Set the animation on the custom view
yourCustomView.startAnimation(a);
}
valueAnimator.setDuration(200);
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
Integer value = (Integer) animation.getAnimatedValue();
view.getLayoutParams().height = value.intValue();
view.requestLayout();
}
});
valueAnimator.start();
}
现在,当您触摸RecyclerView
上的单个卡片视图时(假设您已设置了CardView
),它应该会扩展开来。请确保在xml文件中正确声明您的customView(例如,如果您希望在触摸CardView
时向下扩展,则将其正确分配到其他视图下面并在声明时将其可见性设置为gone,然后在像上面的代码中启动动画时将其可见性设置为Visible并启用视图。)
希望这能帮助到某些人。
CardView
的高度因项目而异,但是“CustomView
”对于所有项目都是相同的。是否可以计算卡片完全展开所需的高度,而不必使其可见?在我的情况下,使用 originalHeight * x
不起作用。 - SanderTuitandroid:animateLayoutChanges="true"
属性。这样,您就不需要编写任何动画代码;但是,如果您需要对动画进行控制,这不是一种可行的方法。OnClickListener
:class CardTapListener implements View.OnClickListener {
@Override
public void onClick(View v) {
View someView = v.findViewById(R.id.view_to_expand);
if (someView.getVisibility() == View.GONE) {
someView.setVisibility(View.VISIBLE);
}
else if (someView.getVisibility() == View.VISIBLE){
someView.setVisibility(View.GONE);
}
}
}
将其附加到每个 ViewHolder
:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.view_holder_layout, viewGroup, false);
v.setOnClickListener(new CardTapListener());
return new ItemViewHolder(v);
}
在绑定新项时,请不要忘记折叠视图:
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int i) {
...
// Collapse (probably opened by user previously) view
ItemViewHolder itemHolder = (ItemViewHolder) viewHolder;
itemHolder.description.setVisibility(View.GONE);
...
}
view_holder_layout.xml:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
...
<AnyViewHere
android:visibility="gone"
android:id="@+id/view_to_expand" />
</LinearLayout>