您的位置:首页 > 移动开发 > Android开发

Android RecyclerView 动画展开item显示详情

2016-08-31 10:51 579 查看
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐