美文网首页Android-CoordinatorLayout.……动画效果
简单实现一个多元素互动的AppBarLayout头部滑动效果

简单实现一个多元素互动的AppBarLayout头部滑动效果

作者: 留给时光吧 | 来源:发表于2018-05-08 20:54 被阅读137次

    效果如下:



    在没有AppBarLayout之前,这种效果实现起来应该是挺复杂的,但是引入AppBarLayout后就很随意了,先看布局文件:

    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:background="@color/colorTransparent"
            android:id="@+id/app_bar"
            app:elevation="0dp"
            >
            <include layout="@layout/layout_weather_head"/>
        </android.support.design.widget.AppBarLayout>
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/ns"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:descendantFocusability="blocksDescendants"
                >
                <com.app.chenyang.sweather.ui.widget.WeatherChartView
                    android:id="@+id/daily_chart"
                    android:layout_width="match_parent"
                    android:layout_height="230dp"
                    android:layout_marginLeft="15dp"
                    android:layout_marginRight="15dp"/>
                <com.app.chenyang.sweather.ui.widget.MyGridView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:id="@+id/gv_living_details"
                    android:numColumns="2"
                    >
                </com.app.chenyang.sweather.ui.widget.MyGridView>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.CoordinatorLayout>
    

    我们那些随着滑动互动的元素就主要就是放在AppBarLayout中。这个布局有几个关键点。

    • 1 AppBarLayout的app:elevation属性要为0dp,否则AppBarLayout下面会有一条横线,影响效果。其次背景要为透明
    • 2 NestedScrollView的app:layout_behavior为@string/appbar_scrolling_view_behavior
      1. AppBarLayout内部的布局layout_weather_head根布局要为RelativeLayout或者FrameLayout,若为Linerlayout则单个元素的移动会受影响。然后app:layout_scrollFlags属性要为"scroll|exitUntilCollapsed|snap"。最后要有最小高度,否则会使整个AppBarLayout划出去,如android:minHeight="100dp"。这个布局比较长就不贴出来了,布局内容可以根据需求自定

    接下来看java代码。我们的效果是随着滑动来改变各个元素的位置,所以就要监听AppBarLayout的滑动事件,由于一些控件可能会未加载完成,导致测量出一些数据为0,我们首先添加一个布局监听,可以任意找一个AppBarLayout内的控件添加:

    tvCity.getViewTreeObserver().addOnGlobalLayoutListener(this);
    

    在布局建立后我们就能拿到每个控件的真实数据,然后根据滑动的距离来动态的改变每个控件位置及其他属性,逻辑不复杂,只不过要有比较缜密的计算,具体实现如下,主要部分有注释:

        @Override
        public void onGlobalLayout() {
            tvCity.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            nestedScrollView.fullScroll(View.FOCUS_UP);
            int ivArrowDistance = ivPageBack.getRight();
            //获取AppBarLayout最大滑动距离
            final int scrollRange = appBar.getTotalScrollRange();
            //预先计算各个部分要移动的距离
            final double tvCityLeftTranslationDistance = tvCity.getLeft() + (tvCity.getWidth() * ZOOM_RATIO * 0.5) - ivArrowDistance;
            final double tvTimeLeftTranslationDistance = tvTime.getLeft() + (tvTime.getWidth() * ZOOM_RATIO * 0.5) - ivArrowDistance;
            final double llWeatherRightTranslationDistance = (BaseUtils.SCREEN_WIDTH - llWeather.getRight()) + (llWeather.getWidth() * ZOOM_RATIO * 0.5) - ivArrowDistance;
            final double llWeatherTopTranslationDistance = ivPageForwardTopMargin + scrollRange/2 + ivPageBack.getHeight() * 0.5 - llWeather.getHeight() * 0.5 - llWeatherTopMargin;
    
            appBar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
                @Override
                public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                    //获得滑动具体,计算比例
                    int scrollDistance = Math.abs(verticalOffset);
                    float scrollPercentage = (float) scrollDistance/scrollRange;
                    
                    //两端箭头处理,主要是随着滑动上下移动
                    ivPageBackParams.topMargin = ivPageBackTopMargin + scrollDistance/2;
                    ivPageForwardParams.topMargin = ivPageForwardTopMargin + scrollDistance/2;
                    ivPageBack.setLayoutParams(ivPageBackParams);
                    ivPageForward.setLayoutParams(ivPageForwardParams);
    
                    //底部AQI和天气文字的处理,只要是设置透明度
                    if(scrollDistance > ALPHA_DISTANCE){
                        tvAQI.setAlpha(0);
                        tvWeather.setAlpha(0);
                    }else{
                        tvAQI.setAlpha(1-scrollDistance/(float)ALPHA_DISTANCE);
                        tvWeather.setAlpha(1-scrollDistance/(float)ALPHA_DISTANCE);
                    }
    
                    //第一行城市名称及时间的处理
                    //向上滑动时文字向右移动且适当缩小
                    tvCityParams.topMargin = tvCityTopMargin + scrollDistance;
                    tvCityParams.leftMargin = -(int) (tvCityLeftTranslationDistance * scrollPercentage);
    
                    tvTimeParams.topMargin = tvTimeTopMargin + scrollDistance;
                    tvTimeParams.leftMargin = -(int) (tvTimeLeftTranslationDistance * scrollPercentage);
    
                    tvCity.setLayoutParams(tvCityParams);
                    tvCity.setScaleX(1 - ZOOM_RATIO * scrollPercentage);
                    tvCity.setScaleY(1 - ZOOM_RATIO * scrollPercentage);
    
                    tvTime.setLayoutParams(tvTimeParams);
                    tvTime.setScaleX(1 -ZOOM_RATIO * scrollPercentage);
                    tvTime.setScaleY(1 -ZOOM_RATIO * scrollPercentage);
    
                    //这里将天气图标和温度作为一整块处理
                    //向上滑动时整体右移且缩小
                    llWeatherParams.topMargin = (int) (llWeatherTopTranslationDistance * scrollPercentage) + llWeatherTopMargin;
                    llWeatherParams.rightMargin = -(int) (llWeatherRightTranslationDistance * scrollPercentage);
                    llWeather.setScaleX(1 - ZOOM_RATIO * scrollPercentage);
                    llWeather.setScaleY(1 - ZOOM_RATIO * scrollPercentage);
                }
            });
    
        }
    

    起始这种方法是比较直接原始的,也很简单,就是实现起来比较繁琐,以后遇到更简便的方法在更新ヾ(o・ω・)ノ

    相关文章

      网友评论

        本文标题:简单实现一个多元素互动的AppBarLayout头部滑动效果

        本文链接:https://www.haomeiwen.com/subject/efrwrftx.html