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对其进行使用. 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我 ...
随机推荐
- atitit.数据验证--db数据库数据验证约束
atitit.数据验证--db数据库数据验证约束 1. 为了加强账户数据金额的安全性,需要增加验证字段..1 2. 创建帐户1 3. 更改账户2 4. ---code3 5. --fini4 1. 为 ...
- 转 #ifndef/#define/#endif使用详解
想必很多人都看过“头文件中的 #ifndef/#define/#endif 防止该头文件被重复引用”.但是是否能理解“被重复引用”是什么意思?是不能在不同的两个文件中使用include来包含这个头文件 ...
- JavaScript SetInterval与setTimeout使用方法详解
setTimeout和setInterval的语法相同.它们都有两个参数,一个是将要执行的代码字符串,还有一个是以毫秒为单位的时间间隔,当过了那个时间段之后就将执行那段代码.不过这两个函数还是有区别的 ...
- google不能访问的根本解决方法
最近中国的防火墙又调皮了.直接出现404了.以前通过IP访问的方式也失效了.难道这种问题能难倒我们这些做技术的IT工程师么?! 经过我的查询,我发现还是有大神在研究这块的.大神针对开发经常访问的网站做 ...
- composer快速入门
composer.json 文件内容定义 ====================================================={ "require":{ &q ...
- nodejs 小爬虫
编写爬虫示例: var http = require('http'); var cheerio = require('cheerio'); var url = 'http://www.cnblogs. ...
- 1.2 基础知识——关于猪皮(GP,Generic Practice)
摘要: 这是<CMMI快乐之旅>系列文章之一.说起猪皮(GP,Generic Practice),真的让人又爱又恨,中文翻译叫通用实践.CMMI标准中每个级别包含几个PA,每个PA又包含几 ...
- yii2集成富文本编辑器redactor
作者:白狼 出处:http://www.manks.top/article/yii2_redactor本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保 ...
- java.lang.OutOfMemoryError处理错误
内存详解 原因: 常见的有以下几种: 1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据: 2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收: 3.代码中存在死循环或循环产生过多 ...
- Win7家庭组的使用
Win7中有两种方式与他人共享文件,一种是“家庭组”,另一种是使用“工作组或域”. 家庭组是Win7中新增的一种共享文件方式,在传统的共享文件方式中必须手动设置所要共享的文件夹,而家庭组则不需要,只需 ...