【问题标题】:Slide down effect on ExpandableListViewExpandableListView 上的向下滑动效果
【发布时间】:2012-02-05 12:11:37
【问题描述】:

是否可以在展开/折叠 ExpandableListView 的项目时产生很好的上/下滑动效果?

如果是,怎么做?

提前致谢。

【问题讨论】:

  • 也许有一种简单的方法可以降低 ExpandableListView 上展开效果的速度。有没有办法???
  • 只有我一个人想知道如何做到这一点????
  • 您找到解决方案了吗?谢谢。
  • 不,我没有。我想我们必须让 Android 实现一个不错的小部件。 ;-)
  • 你有没有解决可扩展列表视图的方法

标签: android expandablelistview expand slidedown slideup


【解决方案1】:

所以这是this 的完整副本。简而言之,我使用了一个常规列表,制作了自己的下拉视图,使用了自定义下拉动画并​​且成功了(查看链接了解更多描述)。

编辑:分步指南:

首先我创建 xml list_row:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/row_parent"
    android:orientation="vertical">
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/row_simple_parent"
        >
    <View
        android:id="@+id/row_simple_parent_invis_cover"
        android:visibility="gone"
        android:layout_height="something that fills out your content"
        android:layout_width="match_parent"
        android:background="@android:color/transparent"/>
    </RelativeLayout>

    <!-- Dropdown -->
    <RelativeLayout 
        android:id="@+id/row_dropdown"
        android:layout_height="wrap_content"
        android:layout_width="match_parent">
    </RelativeLayout>
</LinearLayout>

下拉动画如下:

import android.app.Activity;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.View.MeasureSpec;
import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * Class for handling collapse and expand animations.
 * @author Esben Gaarsmand
 *
 */
public class ExpandCollapseAnimation extends Animation {
    private View mAnimatedView;
    private int mEndHeight;
    private int mStartVisibility;

    /**
     * Initializes expand collapse animation. If the passed view is invisible/gone the animation will be a drop down, 
     * if it is visible the animation will be collapse from bottom
     * @param view The view to animate
     * @param duration
     */ 
    public ExpandCollapseAnimation(View view, int duration) {
        setDuration(duration);
        mAnimatedView = view;
        mEndHeight = mAnimatedView.getLayoutParams().height;
        mStartVisibility = mAnimatedView.getVisibility();
        if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
            mAnimatedView.setVisibility(View.VISIBLE);
            mAnimatedView.getLayoutParams().height = 0;
        }
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        if (interpolatedTime < 1.0f) {
            if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
                mAnimatedView.getLayoutParams().height = (int) (mEndHeight * interpolatedTime);
            } else {
                mAnimatedView.getLayoutParams().height = mEndHeight - (int) (mEndHeight * interpolatedTime);
            }
            mAnimatedView.requestLayout();
        } else {
            if(mStartVisibility == View.GONE || mStartVisibility == View.INVISIBLE) {
                mAnimatedView.getLayoutParams().height = mEndHeight;
                mAnimatedView.requestLayout();
            } else {
                mAnimatedView.getLayoutParams().height = 0;
                mAnimatedView.setVisibility(View.GONE);
                mAnimatedView.requestLayout();
                mAnimatedView.getLayoutParams().height = mEndHeight;
            }
        }
    }

    /**
     * This methode can be used to calculate the height and set itm for views with wrap_content as height. 
     * This should be done before ExpandCollapseAnimation is created.
     * @param activity
     * @param view
     */
    public static void setHeightForWrapContent(Activity activity, View view) {
        DisplayMetrics metrics = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);

        int screenWidth = metrics.widthPixels;

        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);

        view.measure(widthMeasureSpec, heightMeasureSpec);
        int height = view.getMeasuredHeight();
        view.getLayoutParams().height = height;
    }
}

然后在我的适配器中(您当然会添加更多语法,如果您希望下拉列表在列表中看不见时不关闭,您还需要使用某种参数在持有人中记住这一点):

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    final ViewHolder holder;
    if(convertView == null) {
        // setup holder
        holder = new ViewHolder();
        convertView = mInflater.inflate(R.layout.list_row, null);
        holder.mDropDown = convertView.findViewById(R.id.row_dropdown);
        convertView.setTag(holder);
    } else {
        // get existing row view
        holder = (ViewHolder) convertView.getTag();
    }
    holder.mDropDown.setVisibility(View.GONE);
    return convertView;
}

然后魔法发生在您的列表 onItemClick 中:

@Override
public void onListItemClick(ListView list, View view, int position, long id) {
    final ListItem item = (ListItem) list.getAdapter().getItem(position);
    // set dropdown data
    ViewHolder holder = (ViewHolder) view.getTag();
    final View dropDown = holder.mDropDown;

    // set click close on top part of view, this is so you can click the view
    // and it can close or whatever, if you start to add buttons etc. you'll loose
    // the ability to click the view until you set the dropdown view to gone again.
    final View simpleView = view.findViewById(R.id.row_simple_parent_invis_cover);
    simpleView.setVisibility(View.VISIBLE);

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == 0) {
                // first we measure height, we need to do this because we used wrap_content
                // if we use a fixed height we could just pass that in px.
                ExpandCollapseAnimation.setHeightForWrapContent(getActivity(), dropDown);
                ExpandCollapseAnimation expandAni = new ExpandCollapseAnimation(dropDown, DROP_DOWN_TIME);
                dropDown.startAnimation(expandAni);

                Message newMsg = new Message();

            } else if(msg.what == 1) {
                ExpandCollapseAnimation expandAni = new ExpandCollapseAnimation(dropDown, DROP_DOWN_TIME);
                dropDown.startAnimation(expandAni);

                simpleView.setOnClickListener(null);
                simpleView.setVisibility(View.GONE);
            }
        }
    };

    simpleView.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            handler.sendEmptyMessage(1);
        }
    });

    // start drop down animation
    handler.sendEmptyMessage(0);
}

最后的评论:我不确定这是不是最好的方法,但这对我有用。

编辑:在 youtube 上有 DevBytes 提供的不同解决方案,可以查看 here

【讨论】:

  • @Kermia 我稍后会这样做。不确定在这里/在其他帖子或两者中都发布它=/。既然你要求,我想我会在这里发布。
  • 嗨,我正在使用您的示例来制作我自己的动画,但我不知道postDropHandler 是做什么的,如果可能的话,我不知道它是如何实现的。谢谢
  • 我很确定它来自我自己的实现,稍后会清理代码。我用它来判断动画何时结束,这样我就可以在动画结束时做点什么。
  • 我在这里有点困惑(主要是因为我试图在我自己的应用程序中实现您答案中的代码进行测试):onListItemClickgetView 方法适用于 ListView,但是我们在这里使用 ExpandableListView。那么为什么要使用这些 ListView 方法呢?另外,您的ViewHolder 课程是什么?
  • 如果我们想在 ExpandableListView 中为组扩展设置动画,这无济于事。这个解决方案很好,但解决了一个不同的问题。
【解决方案2】:

Warpzit 指出的答案是正确的。我使用这种方法提供了一个库,您可以轻松地将其嵌入到您的应用程序中,而无需了解它的实际工作原理:

https://github.com/tjerkw/Android-SlideExpandableListView

可以在这篇博文中阅读有关它的更多信息: http://tjerktech.wordpress.com/2012/06/23/an-emerging-android-ui-pattern-for-contextual-actions/

【讨论】:

    【解决方案3】:

    在java类中试试这个

           expListView.setAdapter(listAdapter);
        expListView.setOnGroupExpandListener(new OnGroupExpandListener() {
            int previousGroup = -1;
    
            @Override
            public void onGroupExpand(int groupPosition) {
                if(groupPosition != previousGroup)
                    expListView.collapseGroup(previousGroup);
                previousGroup = groupPosition;
            }
        });
    

    【讨论】:

      【解决方案4】:

      Warpzit 的实现确实有效,但是如果您需要支持有很多孩子(比如说 100 个)的组,它就无法使用,因为您不会使用 ListView 的优化结构(即重用/回收子视图)。相反,我最终扩展 ExpandableListView 以创建一个 AnimatedExpandableListView,它使用我描述的技术here。通过这样做,AnimatedExpandableListView 可以动画组扩展,同时仍然提供最佳性能。 Have a look.

      【讨论】:

        【解决方案5】:

        展开/折叠不适用于此处的代码:https://github.com/tjerkw/Android-SlideExpandableListView,因为来自AbstractSlideExpandableListAdapterOnItemExpandCollapseListener expandCollapseListenernull;动画开始时调用notifiyExpandCollapseListener方法,但监听器是null,因为:你有ActionSlideExpandableListView

        ActionSlideExpandableListView lv = (ActionSlideExpandableListView) findViewById(R.id.list_view);
        SlideExpandableListAdapter slideAdapter = new SlideExpandableListAdapter(adapter,R.id.expandable_toggle_button, R.id.expandable);
        

        然后您设置适配器:lv.setAdapter(slideAdapter);,它从 SlideExpandableListView 调用方法 setAdapter,并创建了一个新的 SlideExpandableListAdapter 实例。

        我是这样改变的: 来自ActionSlideExpandableListViewsetAdapter 方法也将AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener 作为参数,它从SlideExpandableListView 传递给setAdapter 方法。那里 当我创建 SlideExpandableListAdapter 时,我也传递了这个监听器:

         public void setAdapter(ListAdapter adapter, AbstractSlideExpandableListAdapter.OnItemExpandCollapseListener expandCollapseListener) {
                this.adapter = new SlideExpandableListAdapter(adapter, expandCollapseListener);
                super.setAdapter(this.adapter);
            }
        
            public SlideExpandableListAdapter(ListAdapter wrapped, OnItemExpandCollapseListener expandCollapseListener) {
                this(wrapped, R.id.expandable_toggle_button, R.id.expandable);
                setItemExpandCollapseListener(expandCollapseListener);
            }
        

        【讨论】:

          【解决方案6】:

          一个简单的解决方案是使用由 Gary Guo 创建的 hereAnimatedExpandableListView,如果您已经在使用扩展 ExpandableListAdapterBaseExpandableListAdapter。这样就不需要使用ListView的修改。

          您只需要继承AnimatedExpandableListAdapter 而不是BaseExpandableListAdapterAnimatedExpandableListView 来代替ExpandableListView

          只需使用@Override getRealChildrenCount,而不是@Override getChildrenCount。对@Override getChildView, 执行相同的操作,使用@Override getRealChildView 代替它。

          然后你像这样使用动画:

              expandableListView.setOnGroupClickListener(new AnimatedExpandableListView.OnGroupClickListener() {
                  @Override
                  public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                      if (expandableListView.isGroupExpanded(groupPosition))
                          expandableListView.collapseGroupWithAnimation(groupPosition);
                      else
                          expandableListView.expandGroupWithAnimation(groupPosition);
                      return true;
                  }
          
              });
          

          另一个细节是,在您的布局 xml 文件中,您需要引用 AnimatedExpandableListView 而不是 ExpandableListView

          <com.your.package.project.class.location.AnimatedExpandableListView
              android:id="@+id/listView"
              android:layout_width="match_parent"
              android:layout_height="match_parent" />
          

          如果需要进一步的帮助,项目中的示例代码和AnimatedExpandableListView 类上的 cmets 非常有用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多