gpt4 book ai didi

android - 回收站查看问答

转载 作者:IT王子 更新时间:2023-10-28 23:31:21 25 4
gpt4 key购买 nike

我正在创建一个问答,其中每个问题都是一张卡片。答案开始显示第一行,但当点击它时,它应该展开以显示完整的答案。

当答案展开/折叠时,RecyclerView 的其余部分应进行动画处理,以便为展开或折叠腾出空间以避免显示空白。

我在 RecyclerView animations 上观看了演讲,并相信我想要一个自定义的 ItemAnimator,我在其中覆盖 animateChange。那时我应该创建一个 ObjectAnimator 来为 View 的 LayoutParams 的高度设置动画。不幸的是,我很难将它们联系在一起。我在覆盖 canReuseUpdatedViewHolder 时也返回了 true,所以我们重用了同一个 viewholder。

@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}


@Override
public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
@NonNull final RecyclerView.ViewHolder newHolder,
@NonNull ItemHolderInfo preInfo,
@NonNull ItemHolderInfo postInfo) {
Log.d("test", "Run custom animation.");

final ColorsAdapter.ColorViewHolder holder = (ColorsAdapter.ColorViewHolder) newHolder;

FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) holder.tvColor.getLayoutParams();
ObjectAnimator halfSize = ObjectAnimator.ofInt(holder.tvColor.getLayoutParams(), "height", params.height, 0);
halfSize.start();
return super.animateChange(oldHolder, newHolder, preInfo, postInfo);
}

现在我只是想制作一些动画,但没有任何反应......有什么想法吗?

最佳答案

我认为您的动画无法正常工作,因为您无法以那种方式为 LayoutParams 设置动画,尽管如果可以的话,它会很整洁。我尝试了你的代码,它所做的只是让我的观点跳到了新的高度。我发现让它工作的唯一方法是使用 ValueAnimator,如下例所示。

在使用 DefaultItemAnimator 通过更新其可见性来显示/隐藏 View 时,我注意到了一些缺点。尽管它确实为新 View 腾出了空间并根据可展开 View 的可见性上下动画其余项目,但我注意到它没有为可展开 View 的高度设置动画。它只是使用 alpha 值简单地淡入淡出。

下面是一个自定义 ItemAnimator,它具有基于在 ViewHolder 布局中隐藏/显示 LinearLayout 的大小和 alpha 动画。它还允许重用相同的 ViewHolder 并在用户快速点击标题时尝试正确处理部分动画:

public static class MyAnimator extends DefaultItemAnimator {
@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}

private HashMap<RecyclerView.ViewHolder, AnimatorState> animatorMap = new HashMap<>();

@Override
public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull final RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
final ValueAnimator heightAnim;
final ObjectAnimator alphaAnim;

final CustomAdapter.ViewHolder vh = (CustomAdapter.ViewHolder) newHolder;
final View expandableView = vh.getExpandableView();
final int toHeight; // save height for later in case reversing animation

if(vh.isExpanded()) {
expandableView.setVisibility(View.VISIBLE);

// measure expandable view to get correct height
expandableView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
toHeight = expandableView.getMeasuredHeight();
alphaAnim = ObjectAnimator.ofFloat(expandableView, "alpha", 1f);
} else {
toHeight = 0;
alphaAnim = ObjectAnimator.ofFloat(expandableView, "alpha", 0f);
}

heightAnim = ValueAnimator.ofInt(expandableView.getHeight(), toHeight);
heightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
expandableView.getLayoutParams().height = (Integer) heightAnim.getAnimatedValue();
expandableView.requestLayout();
}
});

AnimatorSet animSet = new AnimatorSet()
.setDuration(getChangeDuration());
animSet.playTogether(heightAnim, alphaAnim);
animSet.addListener(new Animator.AnimatorListener() {
private boolean isCanceled;

@Override
public void onAnimationStart(Animator animation) { }

@Override
public void onAnimationEnd(Animator animation) {
if(!vh.isExpanded() && !isCanceled) {
expandableView.setVisibility(View.GONE);
}

dispatchChangeFinished(vh, false);
animatorMap.remove(newHolder);
}

@Override
public void onAnimationCancel(Animator animation) {
isCanceled = true;
}

@Override
public void onAnimationRepeat(Animator animation) { }
});

AnimatorState animatorState = animatorMap.get(newHolder);
if(animatorState != null) {
animatorState.animSet.cancel();

// animation already running. Set start current play time of
// new animations to keep them smooth for reverse animation
alphaAnim.setCurrentPlayTime(animatorState.alphaAnim.getCurrentPlayTime());
heightAnim.setCurrentPlayTime(animatorState.heightAnim.getCurrentPlayTime());

animatorMap.remove(newHolder);
}

animatorMap.put(newHolder, new AnimatorState(alphaAnim, heightAnim, animSet));

dispatchChangeStarting(newHolder, false);
animSet.start();

return false;
}

public static class AnimatorState {
final ValueAnimator alphaAnim, heightAnim;
final AnimatorSet animSet;

public AnimatorState(ValueAnimator alphaAnim, ValueAnimator heightAnim, AnimatorSet animSet) {
this.alphaAnim = alphaAnim;
this.heightAnim = heightAnim;
this.animSet = animSet;
}
}
}

这是使用稍微修改的 RecyclerView 演示的结果。

enter image description here

更新:

刚刚注意到你的用例在重新阅读问题后实际上有点不同。您有一个 TextView ,只想显示其中的一行,然后将其展开以显示所有行。幸运的是,这简化了自定义动画师:

public static class MyAnimator extends DefaultItemAnimator {
@Override
public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder) {
return true;
}

private HashMap<RecyclerView.ViewHolder, ValueAnimator> animatorMap = new HashMap<>();

@Override
public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder, @NonNull final RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
ValueAnimator prevAnim = animatorMap.get(newHolder);
if(prevAnim != null) {
prevAnim.reverse();
return false;
}

final ValueAnimator heightAnim;
final CustomAdapter.ViewHolder vh = (CustomAdapter.ViewHolder) newHolder;
final TextView tv = vh.getExpandableTextView();

if(vh.isExpanded()) {
tv.measure(View.MeasureSpec.makeMeasureSpec(((View) tv.getParent()).getWidth(), View.MeasureSpec.AT_MOST), View.MeasureSpec.UNSPECIFIED);
heightAnim = ValueAnimator.ofInt(tv.getHeight(), tv.getMeasuredHeight());
} else {
Paint.FontMetrics fm = tv.getPaint().getFontMetrics();
heightAnim = ValueAnimator.ofInt(tv.getHeight(), (int)(Math.abs(fm.top) + Math.abs(fm.bottom)));
}

heightAnim.setDuration(getChangeDuration());
heightAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
tv.getLayoutParams().height = (Integer) heightAnim.getAnimatedValue();
tv.requestLayout();
}
});

heightAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
dispatchChangeFinished(vh, false);
animatorMap.remove(newHolder);
}

@Override
public void onAnimationCancel(Animator animation) { }

@Override
public void onAnimationStart(Animator animation) { }

@Override
public void onAnimationRepeat(Animator animation) { }
});

animatorMap.put(newHolder, heightAnim);

dispatchChangeStarting(newHolder, false);
heightAnim.start();

return false;
}
}

还有新的演示:

enter image description here

关于android - 回收站查看问答,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35207407/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com