为ExpandableListView添加动画效果

11

有没有办法在 Android 中展开可扩展列表时添加动画效果?

我希望当用户点击可扩展列表时,它具有类似于打开滑动抽屉的动画/效果。

它会缓慢移动,直到完全打开。


https://dev59.com/KG855IYBdhLWcg3wGQNM#5582924 - adneal
5个回答

4
我花了很多时间搜索,但没有找到合适的解决方案 - 如果你的布局不仅仅是两个按钮那么现有的解决方案就变得很卡顿。

所以,我创建了自己的ListAdapter,将整个视图缓存成一个Bitmap,然后对缓存的视图执行动画,而不是直接操作视图本身。 这样可以更快速地运行。

在这里:https://github.com/dmitry-zaitsev/ExpandableAdapter

好消息是,你不需要重写大量代码 - 只需在你的适配器周围包装我的ExpandableAdapter,并提供充当切换按钮的视图的ID和保存第二级内容的视图的ID:

new ExpandableAdapter(context, yourAdapter, R.id.switch, R.id.holder);

这就是全部。


不错的解决方案,但这是针对ListView的,而不是像发帖者所问的ExpandableListView。 - havchr
@havchr “ExpandableListView” 基本上没有用处(由于缺乏定制能力),因此该解决方案旨在用一堆“ListView”+“ExpandableAdapter”来替换“ExpandableListView”。 - Dmitry Zaytsev
R.id.holder是什么?我应该传递什么?谢谢。 - Augusto Picciani
@AugustoPicciani 视图的ID将被展开/折叠。实际上,不要使用这个库,它已经过时了。请使用RecyclerView - Dmitry Zaytsev
谢谢,那么我应该使用哪个库?你能提供一个链接吗?再次感谢。 - Augusto Picciani
@AugustoPicciani http://developer.android.com/tools/support-library/features.html#v7-recyclerview - Dmitry Zaytsev

2
我遇到了完全相同的问题。不过我一次性解决了这个问题,并将其开源到了 GitHub 上。 https://github.com/tjerkw/Android-SlideExpandableListView 基本上,你需要将这个项目依赖项包含到你的 Android 项目中。然后将你的ListAdapter包装成一个SlideExpandableListAdapter。包装器会为你的ListView添加幻灯片功能及动画效果。
希望这能对你有所帮助,我已经在两个项目中使用它了。

我已经开始使用你的库,但是发现一旦我开始添加复杂的视图,它很快就会变得缓慢。我认为这可能是因为你正在执行边距动画。有没有什么建议可以解决性能问题? - Kent Andersen
@KentAndersen,实际上,一个拉取请求已经被接受,应该解决了这个问题。您是否正在使用最新版本?如果您仍然遇到问题,请在 GitHub 提交一张详细的工单来解释它。 - TjerkW
但是您还没有使用ExpandableListView。我想要动画展开列表视图的子视图,而不是ListView的子视图。 - anshul
@TjerkW 我正在尝试使用你的库,它似乎在触摸时触发,但没有可见的变化(项目不会展开),日志条目看起来像:anim height -480;有什么想法吗? - amcc
这是用于扩展 listView 单元格的,而不是扩展 ExpandableListView 中的组。 - havchr

2
我已经尝试过让这个工作正常。我找到了一个适用于childViews的解决方案。虽然它不能动画地扩展整个组,但可以在child cells填充扩展留下的空间时动画显示它们。
编辑:在折叠时有一个错误,这将使一些不应该隐藏的单元格变为隐藏状态。这可能与listView中的View回收相关。当我有解决方案时,我会更新通知大家。 使用setOnGroupClickListener中的layoutAnimation进行动画处理
        mResultList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
        @Override
        public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
            if(mResultList.isGroupExpanded(groupPosition)){
                mProgAdap.prepareToCollapseGroup(groupPosition);
                setupLayoutAnimationClose(groupPosition);
                mResultList.requestLayout();
            }else{
                boolean autoScrollToExpandedGroup = false;
                mResultList.expandGroup(groupPosition,autoScrollToExpandedGroup);
                setupLayoutAnimation();
                //*/
            }
            //telling the listView we have handled the group click, and don't want the default actions.
            return true;
        }

        private void setupLayoutAnimation() {
            AnimationSet set = new AnimationSet(true);
            Animation animation = new AlphaAnimation(0.0f, 1.0f);
            animation.setDuration(50);
            set.addAnimation(animation);

            animation = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f);
            animation.setDuration(50);
            set.addAnimation(animation);

            LayoutAnimationController controller = new LayoutAnimationController(set, 0.75f);
            mResultList.setLayoutAnimationListener(null);
            mResultList.setLayoutAnimation(controller);
        }

        private void setupLayoutAnimationClose(final int groupPosition) {
            AnimationSet set = new AnimationSet(true);
            Animation animation = new AlphaAnimation(1.0f, 0.0f);
            animation.setDuration(50);
            animation.setFillAfter(true);
            animation.setFillEnabled(true);
            set.addAnimation(animation);
            animation = new ScaleAnimation(1.0f, 1.0f, 1.0f, 0.0f, 0.5f, 0.0f);
            animation.setDuration(50);
            animation.setFillAfter(true);
            animation.setFillEnabled(true);
            set.addAnimation(animation);
            set.setFillAfter(true);
            set.setFillEnabled(true);
            LayoutAnimationController controller = new LayoutAnimationController(set, 0.75f);
            controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
            mResultList.setLayoutAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {

                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mResultList.collapseGroup(groupPosition);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
            mResultList.setLayoutAnimation(controller);
        }
    });

我们需要进行更多调整,使动画仅适用于展开/折叠组的实际子项。由于我们无法在LayoutAnimationController中过载正确的部分,我们需要创建一个特殊的ViewGroup类。这与“Can LayoutAnimationController animate only specified Views”中使用的技术相同。
在ExpandableListViewAdapter中,我们现在需要一些状态处理来允许或忽略列表中项目上的动画。
    @Override
public void onGroupExpanded(int groupPos){
    super.onGroupExpanded(groupPos);

    int childCount = getChildrenCount(groupPos);
    Log.d("EXPLIST","setting children to be expanded:" + childCount);

    for(int j=0; j < getGroupCount(); j++){
        for(int k=0; k < getChildrenCount(j); k++){
            GoalServiceCell cell =  (GoalServiceCell)getChild(j,k);
            cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
        }
    }

    for(int i=0; i < childCount; i++){
        GoalServiceCell cell =  (GoalServiceCell)getChild(groupPos,i);
        cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_START_EXPAND;

    }

}

public void prepareToCollapseGroup(int groupPos){
    int childCount = getChildrenCount(groupPos);
    for(int j=0; j < getGroupCount(); j++){
        for(int k=0; k < getChildrenCount(j); k++){
            GoalServiceCell cell =  (GoalServiceCell)getChild(j,k);
            cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
        }
    }

    for(int i=0; i < childCount; i++){
        GoalServiceCell cell =  (GoalServiceCell)getChild(groupPos,i);
        cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_START_COLLAPSIN;

    }
}

@Override
public void onGroupCollapsed(int groupPos){
    super.onGroupCollapsed(groupPos);
    int childCount = getChildrenCount(groupPos);
    for(int i=0; i < childCount; i++){
        GoalServiceCell cell =  (GoalServiceCell)getChild(groupPos,i);
        cell.expandAnimState = GoalServiceCell.ExpandAnimState.SHOULD_NOT_ANIMATE;
    }

}

在子项的 ViewHolder 中。
       void expandOrCollapse(GoalServiceCell cell,int position){

        AnimationAverseRelativeLayout hack = (AnimationAverseRelativeLayout)master;
        boolean shouldAnim = cell.expandAnimState == GoalServiceCell.ExpandAnimState.SHOULD_START_EXPAND ||
                             cell.expandAnimState == GoalServiceCell.ExpandAnimState.SHOULD_START_COLLAPSIN;
        hack.setIfShouldAnimate(shouldAnim);

    }

GroupViews也包含在AnimationAverseRelativeLayout中。由于我将“shouldAnimate”默认设置为false,因此不需要对它们进行操作。


我不得不禁用“折叠”动画,因为我从未使其正常工作。如果你只做展开动画,这算是流氓行为吗? - havchr
你确定已经设置了 controller.setOrder(LayoutAnimationController.ORDER_REVERSE); 而不是 ORDER_RANDOM 吗? - havchr
你是否将以下代码更改为 if(mResultList.isGroupExpanded(groupPosition)){ mResultList.collapseGroup(groupPosition); } 以正确禁用折叠动画?原代码如下:if(mResultList.isGroupExpanded(groupPosition)){ mProgAdap.prepareToCollapseGroup(groupPosition); setupLayoutAnimationClose(groupPosition); mResultList.requestLayout(); } - havchr

1
所以我做的是使用普通的ListView,然后在onListItemClick中执行动画。 该动画类似于我在此链接Android animate drop down/up view proper中所做的内容。
但仅适用于行视图的一部分。 行视图在xml中实现如下:
<somelayout>
    <normal>
    </normal>
    <expanded>
    </expanded>
</somelayout>

正常情况下不使用扩展。当激活扩展时,扩展将设置为可见而不是隐藏。在关闭时需要保持控制并将其再次设置为隐藏(请记住这是在您的转换视图中设置的,这些视图会被回收利用)。

如果需要,我可以进一步澄清,但需要放入相当多的代码。


这是用于扩展 listView 单元格的,而不是扩展 ExpandableListView 中的组。 - havchr
1
@havchr 正确,但有时扩展项的内容可以放在常规项中,这个解决方案也可以使用。 - Warpzit

0

在这种情况下,这就是我所做的。

ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(list1, PropertyValuesHolder.ofInt("bottom", currentlistHeight,currentlistHeight*2 ));

这将使listView的高度加倍,并且会动画化。 如果您将当前列表高度设置为ZERO,则会像抽屉一样运作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接