Android控件显示/隐藏时添加动画:ViewSwitcher

需求描述:整个页面有一个头布局和内容显示布局,头布局会根据下面内容区域的上下滑动来隐藏或显示(隐藏或显示时均有动画)。
内容布局可以是任何可以上下滑动的布局。当头布局隐藏时,整个页面都要可以显示内容,所以内容布局高度需match_parent。
这里写图片描述

实现思路:
1.将头布局用ViewSwitcher(ViewSwitcher最多两个子View)包裹,另外在ViewSwitcher中添加一个高度为0dp的布局跟这个头布局进行交替显示。

@Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (getChildCount() >= 2) {
            throw new IllegalStateException("Can't add more than 2 views to a ViewSwitcher");
        }
        super.addView(child, index, params);
    }

2.可以在ViewSwitcher中设置动画。

3.内容布局设置滚动监听,根据上下滑动的偏移量来控制ViewSwitcher具体显示哪个子View。

代码实现:

布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_movie"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <com.example.customview.MyViewSwitcher
        android:id="@+id/viewswitch"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/head"
        android:inAnimation="@anim/slide_in_top"
        android:outAnimation="@anim/slide_out_top"
        android:persistentDrawingCache="animation">

        <LinearLayout
            android:id="@+id/ll_head"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@color/white"
            android:gravity="center">

            <TextView
                android:gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingBottom="6dp"
                android:paddingTop="6dp"
                android:textColor="@color/colorTitle2"
                android:textSize="@dimen/text_size_14"
                android:text="头布局" />

        </LinearLayout>

        <!--高度为0的空布局-->
        <View
            android:layout_width="match_parent"
            android:layout_height="0dp" />

    </com.example.customview.MyViewSwitcher>

</RelativeLayout>

动画文件
slide_in_top.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="-100%p"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:toYDelta="0" />

slide_out_top.xml

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="300"
    android:fromYDelta="0"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:toYDelta="-100%p" />

自定义ViewSwitcher:MyViewSwitcher
在MyViewSwitcher中封装了具体显示哪个子View的方法

public class MyViewSwitcher extends ViewSwitcher {

    /**
     * 真正的头布局
     */
    private View firstChildView;

    /**
     * 高度为0的空布局
     */
    private View secondChildView;

    private static final int DELTA = 400;//根据具体情况设置值的大小

    /**
     * y方向偏移量总和
     */
    private int DY = 0;

    public MyViewSwitcher(Context context) {
        this(context, null);
    }

    public MyViewSwitcher(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        firstChildView = getChildAt(0);
        secondChildView = getChildAt(1);
    }

    /**
     * 根据外部传入的y值来设置显示哪个子View
     * 如果向上滑动了好几页,突然想回到头布局时,只需向下滑动DELTA偏移即可显示头布局(语言功底差,描述不到位,相信大家都懂)
     *
     * @param delta
     */
    public void whichOneShow(int delta) {
        DY += delta;

        //向上滑动
        //当y偏移量总和大于DELTA,且第一个子View显示时,设置第二个子View显示
        if (DY > DELTA && firstChildView.getVisibility() == VISIBLE) {
            DY = 0;
            setDisplayedChild(1);
        } else if (DY > 0 && secondChildView.getVisibility() == VISIBLE) {
            //继续向上滑动,且第二个子View一直处于显示状态,则将偏移量总和置零
            DY = 0;
        }

        //向下滑动
        //当y偏移量总和大于DELTA(即小于[-DELTA]),且第二个子View显示时,设置第一个子View显示
        if (DY < -DELTA && secondChildView.getVisibility() == VISIBLE) {
            DY = 0;
            setDisplayedChild(0);
        } else if (DY < 0 && firstChildView.getVisibility() == VISIBLE) {
            //继续向下滑动,且第一个子View一直处于显示状态,则将偏移量总和置零
            DY = 0;
        }
    }
}

MainActivity

public class MainActivity extends AppCompatActivity{

    private RecyclerView mRecyclerView;

    private MyViewSwitcher mViewSwitch;


    @Override
    public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        setContentView(R.layout.activity_search_movie);
        initViews();
    }


    protected void initViews() {

        mRecyclerView = (RecyclerView) findViewById(R.id.rv_movie);
        mViewSwitch = (MyViewSwitcher) findViewById(R.id.viewswitch);

        //RecyclerView设置数据部分代码省略
        //...


        //根据RecyclerView在竖直方向滑动的偏移量来控制头布局显示/隐藏
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                mViewSwitch.whichOneShow(dy);
            }
        });

    }
}

如有错误或不足之处,欢迎指正。。

猜你喜欢

转载自blog.csdn.net/u011797571/article/details/53814288
今日推荐