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);
        }

    }
}

一个可能会出现的问题

ViewPager每次notifyDataSetChanged之后,所设置的PageTransformer显示就出问题?

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在Fragment中使用ViewPager和Layout来显示页面,可以按照以下步骤进行操作: 1. 在Fragment的布局文件中添加一个ViewPager和一个TabLayout控件。 2. 创建一个PagerAdapter类,继承自FragmentPagerAdapter或FragmentStatePagerAdapter。 3. 在PagerAdapter类中重写getItem()方法,返回对应位置的Fragment对象。 4. 在Fragment的onViewCreated()方法中,获取ViewPager和TabLayout控件,并将PagerAdapter对象设置给ViewPager。 5. 在Fragment中创建多个Fragment对象,并在PagerAdapter中返回这些Fragment对象。 6. 在Fragment中设置TabLayout的标签,可以使用addTab()方法。 7. 运行程序,即可在Fragment中显示ViewPager和Layout来展示页面。 下面是一个简单的示例代码: ``` public class MyFragment extends Fragment { private ViewPager viewPager; private TabLayout tabLayout; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_my, container, false); viewPager = view.findViewById(R.id.viewPager); tabLayout = view.findViewById(R.id.tabLayout); MyPagerAdapter adapter = new MyPagerAdapter(getChildFragmentManager()); viewPager.setAdapter(adapter); tabLayout.addTab(tabLayout.newTab().setText("Tab 1")); tabLayout.addTab(tabLayout.newTab().setText("Tab 2")); tabLayout.setupWithViewPager(viewPager); return view; } private static class MyPagerAdapter extends FragmentPagerAdapter { public MyPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { if (position == 0) { return new Fragment1(); } else { return new Fragment2(); } } @Override public int getCount() { return 2; } @Override public CharSequence getPageTitle(int position) { if (position == 0) { return "Tab 1"; } else { return "Tab 2"; } } } } ``` 在这个示例中,MyFragment是一个包含ViewPager和TabLayout的Fragment。在MyPagerAdapter中,我们创建了两个Fragment对象:Fragment1和Fragment2,并在getItem()方法中根据位置返回对应的Fragment对象。在getPageTitle()方法中,我们设置了TabLayout的标签。最后,在MyFragment的onCreateView()方法中,我们将PagerAdapter对象设置给ViewPager,并将TabLayout的标签与ViewPager关联起来。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值