ViewPager實現子項摺疊,中間突出,兩側顯示部分,並且以陰影顯示

效果圖

先上一個效果圖,看一下實現效果
在這裏插入圖片描述
大概說明一下:最外層佈局,是ViewPager,子項是Fragment,一屏幕顯示5個子項,中間位置突出,兩側子項縮放,並且隱藏在中間子項後邊,用陰影顯示

實現步驟

外層佈局

外層佈局就是一個ViewPager,先定義好:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context=".DemoActivity"
              android:padding="16dp"
              android:background="#ffffff"
              android:clipChildren="false">


    <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:background="#ffffff"
            android:layout_margin="40dp"
    />

</LinearLayout>

兩點說明:1.android:clipChildren,是否限制子View在其範圍內,默認值爲true,也就是不允許進行擴展繪製,這裏設置爲false,還必須是在ViewPager的父佈局設置
2.android:layout_margin=“40dp”, 設置這個,是爲了給ViewPager兩側留出多餘位置,用來顯示兩側陰影

Fragment佈局

首先:Fragment裏,外層佈局是FrameLayout,裏邊有兩個佈局,一個是正常顯示,一個是用來改變透明度,實現陰影效果,這個以後會根據滑動位置,來切換顯示不同佈局,先定義兩個圓角矩形,一個是有陰影外層,作爲正常顯示佈局的背景,另一個是純色,作爲另一個佈局的背景
1.實現有陰影外層的圓角矩形
這個是用layer-list

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
           >
        <shape>
            <corners android:radius="5dp"/>

            <solid android:color="#F5F5F5"/>
        </shape>
    </item>

    <item   android:bottom="5dp"
            android:right="5dp"
            android:left="5dp"
            android:top="5dp">
        <shape>
            <corners android:radius="5dp"/>
            <solid android:color="#ffffff"/>
        </shape>
    </item>
</layer-list>

2.純色的圓角矩形

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <!-- 填充顏色 -->
    <solid android:color="#4184f5"/>

    <!-- 線的寬度,顏色藍色 -->
    <stroke android:width="1dp" android:color="#4184f5"/>

    <!-- 矩形的圓角半徑 -->
    <corners android:radius="5dp" />

</shape>

有了這兩個背景,剩下的就是佈局,也很簡單

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="300dp">
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="vertical"
                  android:id="@+id/ll_info"
                  android:layout_margin="5dp"
                  android:background="@drawable/rect_solid_and_stroke_white_corner_5dp"
    >
        <LinearLayout
                android:id="@+id/ll_top"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:padding="16dp"
                android:gravity="center_vertical"
        >
            <ImageView
                    android:id="@+id/iv_image"
                    android:layout_width="180dp"
                    android:layout_height="180dp"
                    android:layout_gravity="center"
                    android:scaleType="fitXY"/>

            <TextView android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:textColor="@color/colorAccent"
                      android:layout_margin="10dp"
                      android:text="我是進度條"/>
            <ProgressBar
                    android:id="@+id/new_people_progress"
                    android:layout_width="match_parent"
                    android:layout_height="12dp"
                    android:layout_margin="16dp"
                    android:max="100"
                    android:progress="40"
                    style="?android:attr/progressBarStyleHorizontal"
                    android:progressDrawable="@drawable/progressbar_color"/>

        </LinearLayout>

    </LinearLayout>
    <LinearLayout
            android:id="@+id/ll_zhegai"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/rect_solid_and_stroke_4184f5_corner_5dp"
            android:orientation="horizontal"
            android:visibility="gone"/>
</FrameLayout>

3.進度條效果:
佈局中,有一個進度條的效果,實現這樣的效果,也是需要使用layer-list,但是自定義的時候,希望進度條兩側都是圓角矩形,但是一般會clip成直角,這個解決方法,是自定義個shape去引用

<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

    <item android:id="@android:id/background"
          android:layout_width="wrap_content">
        <shape>
            <corners android:radius="10dp" />

            <solid android:color="#f4f4f4" />
        </shape>
    </item>
    <!-- 進度條 -->
    <item android:id="@android:id/progress">
        <scale android:scaleWidth="100%"
               android:drawable="@drawable/progress_bar_ct"   />
    </item>


</layer-list>

progress_bar_ct.xml

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

    <item>

        <shape>

            <solid android:color="#2583fd" />
            <!-- padding設置內容區域離邊界的間距 -->
            <!-- corners設置圓角,只適用於rectangle -->
            <corners android:radius="10dp"/>

        </shape>

    </item>

</selector>

Android佈局實現陰影效果

Fragment代碼

Fragment作爲演示,功能很簡單,根據定義,加載不同圖片

public class PictureFragment extends Fragment
{
    // TODO: Rename parameter arguments, choose names that match
    // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
    private static final String ARG_PARAM1 = "param1";
    private static final String ARG_PARAM2 = "param2";

    // TODO: Rename and change types of parameters
    private int mParam1;

    public PictureFragment()
    {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @return A new instance of fragment PictureFragment.
     */
    // TODO: Rename and change types and number of parameters
    public static PictureFragment newInstance(int param1)
    {
        PictureFragment fragment = new PictureFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_PARAM1, param1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        if (getArguments() != null)
        {
            mParam1 = getArguments().getInt(ARG_PARAM1);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_picture, container, false);
        ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
        imageView.setBackgroundResource(mParam1);
        return view;
    }

    @Override
    public void onAttach(Context context)
    {
        super.onAttach(context);

    }

    @Override
    public void onDetach()
    {
        super.onDetach();
    }


}

Activity代碼

{
.............
 fragments.add(PictureFragment.newInstance(R.mipmap.p1));
        fragments.add(PictureFragment.newInstance(R.mipmap.p2));
        fragments.add(PictureFragment.newInstance(R.mipmap.p3));
        fragments.add(PictureFragment.newInstance(R.mipmap.p4));
        fragments.add(PictureFragment.newInstance(R.mipmap.p5));
        fragments.add(PictureFragment.newInstance(R.mipmap.p6));
        fragments.add(PictureFragment.newInstance(R.mipmap.p7));
        CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager(), fragments);
        viewPager.setPageTransformer(true, new CustomTransformer(DemoActivity.this));
        viewPager.setAdapter(customPagerAdapter);
        viewPager.setOffscreenPageLimit(5);

    }

    public class CustomPagerAdapter extends FragmentStatePagerAdapter
    {

        private List<Fragment> mFragments;

        public CustomPagerAdapter(FragmentManager fm, List<Fragment> fragments)
        {
            super(fm);
            this.mFragments = fragments;
            fm.beginTransaction().commitAllowingStateLoss();
        }

        @Override
        public Fragment getItem(int position)
        {
            return this.mFragments.get(position);
        }

        @Override
        public int getCount()
        {
            return this.mFragments.size();
        }

        @Override
        public int getItemPosition(@NonNull Object object)
        {
            return PagerAdapter.POSITION_NONE;
        }
    }

說明:1.Viewpager的setOffscreenPageLimit(int limit)方法,設置有多少的緩存Views
2.Viewpager的setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer)方法的第一個參數,用來控制加入到Viewpager的Views對象是正序的還是倒序的

特效實現

Viewpager實現特效,主要通過PageTransformer接口,不熟悉的可以先了解一下
Android ViewPager.PageTransformer詳解
Android——ViewPager實現3D畫廊效果
ViewPager實現層疊卡片
Android ViewPager使用方法小結

現在開始實現效果圖中的特效:
1.正常情況下,子項是不折疊到一起,通過設置 view.setTranslationX,按照子項寬度進行和位置進行平移,這樣才能摺疊到一起,pageWidth* position,爲了實現效果圖上左右兩側露出部分,可以通過改變偏移量實現,比如pageWidth * 0.9f * position之類
2.實現中間位置突出。設置摺疊後,正常情況下,後邊子項會遮蓋在前一子項上邊,這個通過設置setTranslationZ可以改變,這個translationZ設置view的層級,translationZ越大,說明他的層級越高,所以position = -1的view的層級就比position=0的view的層級低,那麼position=0的view就會疊在position=-1的view的上面,除中間位置以外,其他子項,都設置低一些,這樣才能突出中間子項
3.縮放可以通過view.setScaleX和 view.setScaleY來實現,設置不同的值,縮放不同的大小,通過這個,可以實現,最外層比次外層小的效果
4.除中間位置以外,其他位置,切換到純色背景,設置透明度,

public class CustomTransformer implements ViewPager.PageTransformer
{
    private static final float MIN_SCALE = 0.85f;
    private static final float MIN_ALPHA = 0.8f;

    private static float defaultScale = 0.5f;
    private Context context;

    public CustomTransformer(Context context)
    {
        this.context = context;
    }

    @Override
    public void transformPage(View view, float position)
    {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();
        float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
        //一個頁面顯示5個子項,最左側的位置是-2,小於-2的,設置透明度爲0,隱藏
        if (position < -2)
        {
            view.setAlpha(0);
            view.setScaleX(defaultScale);
            view.setScaleY(defaultScale);
        }
        else if (position >= -2 && position <= -1)
        {   //中間位置左側的兩個子項
            //設置透明度
            view.setAlpha(0.1f);
            // view.setAlpha((MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA))*0.5f);

            if (position < -1 && position >= -2)//最左側子項,比前一子項縮放更小一些
            {
                view.setScaleX(scaleFactor * 0.9f);
                view.setScaleY(scaleFactor * 0.9f);
            }
            else
            {
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            }
            /**
             這個translationZ設置view的層級,translationZ越大,說明他的層級越高

             所以position = -1的view的層級就比position=0的view的層級低,
             那麼position=0的view就會疊在position=-1的view的上面,
             除中間位置以外,其他子項,都設置低一些,這樣才能突出中間子項
             */
            view.setTranslationZ(position);
            //按照子項寬度進行和位置進行平移,這樣才能摺疊到一起
            view.setTranslationX((-pageWidth * 0.9f * position));
            //除中間位置顯示正常佈局以外,其他佈局,使用純色背景,並且設置透明度顯示
            view.findViewById(R.id.ll_info).setVisibility(View.INVISIBLE);
            view.findViewById(R.id.ll_zhegai).setVisibility(View.VISIBLE);

        }
        else if (position < 1)
        { // [-1,1]
            // Modify the default slide transition to shrink the page as well

            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            //中間位置透明度
            if (position == 0)
            {
                view.setAlpha(1);
            }
            else
            {
                //中間位置滑動到兩側過程中,透明度變化
                view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
            }

            view.findViewById(R.id.ll_info).setVisibility(View.VISIBLE);
            view.findViewById(R.id.ll_zhegai).setVisibility(View.INVISIBLE);

            if (position != 0)
            {
                view.setTranslationX((-pageWidth * 0.9f * position));
            }
            if (position > 0)
            {
                view.setTranslationZ(-position);
            }
            else
            {
                view.setTranslationZ(position);
            }

            if (position != 0)
            {
                //除中間位置不縮放以外,滑動到其他地方都縮放
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            }


            // Fade the page relative to its size.
            // view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));

        }
        else if (position >= 1 && position <= 2)
        {
            view.setAlpha(0.1f);
            // view.setAlpha((MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA))*0.5f);
            if (position > 1 && position <= 2)
            {
                view.setScaleX(scaleFactor * 0.9f);
                view.setScaleY(scaleFactor * 0.9f);
            }
            else
            {
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);
            }

            /**
             這個translationZ設置view的層級,translationZ越大,說明他的層級越高

             所以position = -1的view的層級就比position=0的view的層級低,那麼position=0的view就會疊在

             position=-1的view的上面,除中間位置以外,其他子項,都設置低一些,這樣才能突出中間子項
             */
            view.setTranslationZ(-position);
            //按照子項寬度進行和位置進行平移,這樣才能摺疊到一起
            view.setTranslationX((-pageWidth * 0.9f * position));

            //除中間位置顯示正常佈局以外,其他佈局,使用純色背景,並且設置透明度顯示
            view.findViewById(R.id.ll_info).setVisibility(View.INVISIBLE);
            view.findViewById(R.id.ll_zhegai).setVisibility(View.VISIBLE);

        }
        else
        {   //右側第二個子項以外,設置透明度爲0,不可見
            view.setAlpha(0);
            view.setScaleX(defaultScale);
            view.setScaleY(defaultScale);
            view.setTranslationZ(-position);
        }

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章