Android RecyclerView 动画展开item显示详情
stackoverflow上看到这个问题,答主给了个demo
http://stackoverflow.com/questions/27446051/recyclerview-animate-item-resize
看懂了之后发个博,记录一下,刚开始看别人代码好难受,就这么3个文件看了一晚上。。
效果如下
res文件
main_activity文件就是一个recyclerview
main_item是两个textview 一个标题一个详细信息
MainActivity就是加载了一个RecyclerView
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
final RecyclerView rv = (RecyclerView) findViewById(R.id.rv);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
rv.setLayoutManager(layoutManager);
final MainAdapter adapter = new MainAdapter();
rv.setAdapter(adapter);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
MainAdapter中new了一个keepOne对象,点进去看这个类,有两个方法:bind和toggle,其中的bind是在MainAdapter中的onBindViewHolder()方法中调用,而toggle是响应viewholder的点击事件
public static class KeepOneH<VH extends RecyclerView.ViewHolder & Expandable> {
// opened为-1表示所有item是关闭状态,open为pos值的表示pos位置的item为展开的状态
private int _opened = -1;
public void bind(VH holder, int pos) {
if (pos == _opened)
// 3
// 直接显示expandView 无动画
ExpandableViewHoldersUtil.openH(holder, holder.getExpandView(), false);
else
// 直接关闭expandView 无动画
ExpandableViewHoldersUtil.closeH(holder, holder.getExpandView(), false);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
@SuppressWarnings("unchecked")
// 响应点击事件的方法
public void toggle(VH holder) {
// 如果点击的就是开着的item,就关闭该item并把opened置-1
// ???TODO
if (_opened == holder.getPosition()) {
_opened = -1;
// 关闭expandView 有动画
ExpandableViewHoldersUtil.closeH(holder, holder.getExpandView(), true);
}
// 如果点击其他本来关闭着的item,则把opened值换成当前pos,把之前开的item给关掉
else {
int previous = _opened;
_opened = holder.getPosition();
// 展开expandView 有动画
ExpandableViewHoldersUtil.openH(holder, holder.getExpandView(), true);
// 用动画关闭之前的item
final VH oldHolder = (VH) ((RecyclerView) holder.itemView.getParent()).findViewHolderForPosition(previous);
if (oldHolder != null)
ExpandableViewHoldersUtil.closeH(oldHolder, oldHolder.getExpandView(), true);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
点进openH和closeH方法进去看
// 4
public static void openH(final RecyclerView.ViewHolder holder, final View expandView, final boolean animate) {
// animate参数为true,则有动画效果
if (animate) {
expandView.setVisibility(View.VISIBLE);
// 5
// 改变高度的动画,具体操作点进去看
final Animator animator = ViewHolderAnimator.ofItemViewHeight(holder);
// 扩展的动画结束后透明度动画开始
animator.addListener(new AnimatorListenerAdapter() {
@Override public void onAnimationEnd(Animator animation) {
final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(expandView, View.ALPHA, 1);
alphaAnimator.addListener(new ViewHolderAnimator.ViewHolderAnimatorListener(holder));
alphaAnimator.start();
}
});
animator.start();
}
// animate参数为false,则直接设置为可见
else {
expandView.setVisibility(View.VISIBLE);
expandView.setAlpha(1);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
openH方法接收3个参数,
第一个是viewholder.
第二个是展开部分的view,由holder.getExpandView()方法获取。这里定义了一个接口
public static interface Expandable {
public View getExpandView();
}
- 1
- 2
- 3
- 1
- 2
- 3
在MainAdapter中传入infos这个Textview
@Override
public View getExpandView() {
return infos;
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
第三个是一个标记,true时有动画,false时直接设置其展开或者是关闭的状态。所以在bind()方法中调用的openH()都是false,而toggle()中调用的设置为true。
openH方法中 具体动画的操作为ViewHolderAnimator.ofItemViewHeight(holder)
public static Animator ofItemViewHeight(RecyclerView.ViewHolder holder) {
View parent = (View) holder.itemView.getParent();
if (parent == null)
throw new IllegalStateException("Cannot animate the layout of a view that has no parent");
// 测量扩展动画的起始高度和结束高度
int start = holder.itemView.getMeasuredHeight();
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(parent.getMeasuredWidth(), View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
int end = holder.itemView.getMeasuredHeight();
// 6
final Animator animator = LayoutAnimator.ofHeight(holder.itemView, start, end);
// 设定该item在动画开始结束和取消时能否被recycle
animator.addListener(new ViewHolderAnimatorListener(holder));
// 设定结束时这个item的宽高
animator.addListener(new LayoutParamsAnimatorListener(holder.itemView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
return animator;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
可以看出 具体展开的动画在LayoutAnimator.ofHeight(holder.itemView, start, end);中,ViewHolderAnimator只是测量参数,设定监听两个监听事件
1设定在动画开始结束和取消状态下是否可以被回收
public ViewHolderAnimatorListener(RecyclerView.ViewHolder holder) {
_holder = holder;
}
@Override
public void onAnimationStart(Animator animation) {
_holder.setIsRecyclable(false);
}
@Override
public void onAnimationEnd(Animator animation) {
_holder.setIsRecyclable(true);
}
@Override
public void onAnimationCancel(Animator animation) {
_holder.setIsRecyclable(true);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
2.设定在动画结束后view的高和宽分别为warp_content,match_parent.
public static class LayoutParamsAnimatorListener extends AnimatorListenerAdapter {
private final View _view;
private final int _paramsWidth;
private final int _paramsHeight;
public LayoutParamsAnimatorListener(View view, int paramsWidth, int paramsHeight) {
_view = view;
_paramsWidth = paramsWidth;
_paramsHeight = paramsHeight;
}
@Override
public void onAnimationEnd(Animator animation) {
final ViewGroup.LayoutParams params = _view.getLayoutParams();
params.width = _paramsWidth;
params.height = _paramsHeight;
_view.setLayoutParams(params);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
再深入一层看展开的动画
public class LayoutAnimator {
public static class LayoutHeightUpdateListener implements ValueAnimator.AnimatorUpdateListener {
private final View _view;
public LayoutHeightUpdateListener(View view) {
_view = view;
}
@Override
public void onAnimationUpdate(ValueAnimator animation) {
final ViewGroup.LayoutParams lp = _view.getLayoutParams();
lp.height = (int) animation.getAnimatedValue();
_view.setLayoutParams(lp);
}
}
public static Animator ofHeight(View view, int start, int end) {
final ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.addUpdateListener(new LayoutHeightUpdateListener(view));
return animator;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
是用ValueAnimator.ofInt生成一系列高度值,然后监听动画的变化,不断设定view的高度值
http://blog.csdn.net/gulumi_mmga/article/details/46683437
Android RecyclerView 动画展开item显示详情的更多相关文章
- Android解决RecyclerView中的item显示不全方案
最近的项目中实现订单确定页面.需要使用ScrollView嵌套RecyclerView,当RecyclerView中的item数量比较多时,就会出现item只显示一部分数据,并没有将用户勾选的商品数量 ...
- Android RecyclerView预览item
参考: Android Tools Attributes listItem 和 Sample Data 的用法 笔记 tools:text TextView可以实现预览,不影响实际的效果 例如: to ...
- Android Animation动画实战(一): 从布局动画引入ListView滑动时,每一Item项的显示动画
前言: 之前,我已经写了两篇博文,给大家介绍了Android的基础动画是如何实现的,如果还不清楚的,可以点击查看:Android Animation动画详解(一): 补间动画 及 Android An ...
- 解决ScrollView嵌套RecyclerView出现item显示不全的问题
问题:ScrollView嵌套RecyclerView时,RecyclerView的item显示不全 出现问题不要慌,耐心解决才是王道,哈哈.首先说下出现这个问题的情景吧,首先声明这个问题在23版 ...
- 【Android 界面效果49】RecyclerView高度随Item自适应
编写RecyclerView.ItemDecoration时,在onDraw方法中,Drawable的高度等于RecyclerView的高度减去RecyclerView的上下padding. @Ove ...
- Android 自定义View修炼-自定义可动画展开收缩View的实现
有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...
- Android窗口管理服务WindowManagerService显示窗口动画的原理分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8611754 在前一文中,我们分析了Activi ...
- 基于css3的鼠标经过动画显示详情特效
之前为大家分享过一款基于jquery的手风琴显示详情,今天给大家分享基于css3的鼠标经过动画显示详情特效.这款实例鼠标经过的时候基于中间动画放大,效果非常不错,效果图如下: 在线预览 源码下载 ...
- Android RecyclerView 使用完全解析 体验艺术般的控件
概述 RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用. 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我 ...
随机推荐
- Understanding theory (1)
Source: verysmartbrothas.com It has been confusing since my first day as a PhD student about theory ...
- 【ios】使用Block对POST异步操作的简单封装
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3409721.html 一般情况下的POST异步操作需要实现以下 ...
- mac jdk 6设置
新装的mac 系统10.10 ,jdk是1.8,因为一些工具要使用 jdk 6,以下是设置过程 查看版本 java -version 查看java是再哪:在/usr/bin/java whereis ...
- 【Android】友盟的自动更新组件
前言 又好又专业的服务能帮开发者省很多时间.一开始做项目也准备自己来统计数据.自己做自动更新,随着使用友盟服务的时间增加,渐渐放弃了这种想法,转而研究如何更充分的使用,这里分享一下使用自动更新组件的心 ...
- EMC Documentum DQL整理(四)
1.List files and folder in specified folder pathSELECT DISTINCT s.object_name, fr.r_folder_path FROM ...
- 清除ASPX页面中的meta:resourceKey="[a-zA-Z0-9]+"
在替换对话框中,选中“使用正则表达式”, 被替换内容,使用 meta:resourceKey="[a-zA-Z0-9]+" 然后替换整个文档就可以了.
- 大型网站的 HTTPS 实践(1):HTTPS 协议和原理
转自:http://op.baidu.com/2015/04/https-s01a01/ 1 前言 百度已经于近日上线了全站 HTTPS 的安全搜索,默认会将 HTTP 请求跳转成 HTTPS.本文重 ...
- Linux软件的卸载
configure作用:是源码安装软件时配置环境用的 他根据你的配置选项和你的系统情况生成makefile文件 为make 做准备 最常用的参数: ./configure --prefix 作用: 不 ...
- Python基础之set与函数
set集合 set 是无序,不重复的序列,基本功能包括去重和关系测试,集合中没有插入的方法,只能添加. 集合对象还支持union(联合), intersection(交), difference(差) ...
- linux清理内存命令
1.清理前内存使用情况 free -m 2.开始清理 echo 1 > /proc/sys/vm/drop_caches3.清理后内存使用情况 free -m4.完成! 查看内存条数命令: # ...