美文网首页
Android 一个简单的无限循环、带特效的ViewPager

Android 一个简单的无限循环、带特效的ViewPager

作者: DON_1007 | 来源:发表于2019-12-07 16:35 被阅读0次

    实现效果图

    viewpagerdemo.gif

    这个效果是用ViewPager实现的,实现方式为ViewPager + Fragment + PageTransformer。主要功能点有

    • ViewPager+Fragment无限循环,ViewPager的无限循环比较简单的有以ViewPager+View的方式实现,这里使用ViewPager+Fragment是因为FragmentView有更多的方法,更多的属性,以及生命周期以便于灵活的、高效的完成开发任务
    • 通过PageTransformer实现左右两张图片的显示及特效添加
    • 动态修改ViewPager的滑动速度
    • 动态控制ViewPager对连续长按遥控器左右键的事件响应

    一、ViewPager+Fragment无限循环实现

    无限循环功能点的实现主要工作在Adapter中,通过覆写下面4个方法来实现功能

      package com.hpplay.muiltythreaddemo.viewpagerdemo;
    
    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentPagerAdapter;
    import android.view.ViewGroup;
    
    import java.util.ArrayList;
    
    /**
     * Created by DON on 2016/12/30.
     */
    public class ViewPagerAdapter extends FragmentPagerAdapter {
    
        private ArrayList<Integer> dataBeanArrayList;
    
        FragmentManager mFm;
    
        public ViewPagerAdapter(FragmentManager fm, ArrayList<Integer> fragmentArrayList) {
            super(fm);
            this.mFm = fm;
            this.dataBeanArrayList = fragmentArrayList;
        }
    
        @Override
        public ItemPagerFragment getItem(int position) {
            int realPosition = position % dataBeanArrayList.size();
            ItemPagerFragment itemViewPagerFragment = new ItemPagerFragment();
            itemViewPagerFragment.setData(dataBeanArrayList.get(realPosition));
            return itemViewPagerFragment;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
    
            ItemPagerFragment itemRecyclerViewPagerFragment = (ItemPagerFragment)
                    super.instantiateItem(container, position);
            return itemRecyclerViewPagerFragment;
        }
    
        @Override
        public int getItemPosition(Object object) {
            return POSITION_NONE;
        }
    
        @Override
        public int getCount() {
            return dataBeanArrayList.size() <= 1 ? dataBeanArrayList.size() : Integer.MAX_VALUE;
        }
    
    
    }
    
    

    上面ItemPagerFragmentViewPager内嵌的Fragment,用于展示具体的图片。
    新建类ViewPagerFragment ,实现ViewPager代码

    package com.hpplay.muiltythreaddemo.viewpagerdemo;
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.support.v4.view.ViewPager;
    import android.view.KeyEvent;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.AccelerateInterpolator;
    
    import com.hpplay.muiltythreaddemo.R;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    
    /**
     * Created by DON on 2017/7/24.
     */
    
    public class ViewPagerFragment extends Fragment {
        private ViewPager viewPager;
        private ViewPagerAdapter pagerAdapter;
        private ArrayList<Integer> dataBeanArrayList = new ArrayList<>();
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            return View.inflate(getActivity(), R.layout.f_viewpager, null);
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            viewPager = (ViewPager) view.findViewById(R.id.viewPager);
    
            int drawable[] = {R.drawable.im1, R.drawable.im2, R.drawable.im3, R.drawable.im4, R.drawable.im5};
            for (int i = 0; i < drawable.length; i++) {
                dataBeanArrayList.add(drawable[i]);
            }
    
            pagerAdapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager()
                    , dataBeanArrayList);
            viewPager.setAdapter(pagerAdapter);
            viewPager.setPageTransformer(true, new PageTransformer());
            viewPager.setOffscreenPageLimit(2);
            viewPager.setFocusable(true);
            viewPager.setFocusableInTouchMode(true);
    
            if (dataBeanArrayList.size() > 1) {
                int position = Integer.MAX_VALUE / 2;
                while (position % dataBeanArrayList.size() > 0) {
                    ++position;
                }
                viewPager.setCurrentItem(position);//保证ViewPager当前显示的是第一个数据
            }
            pagerAdapter.notifyDataSetChanged();
        }
    }
    
    

    ItemPagerFragment作为ViewPager内嵌的Fragment,实现如下

    package com.hpplay.muiltythreaddemo.viewpagerdemo;
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    
    import com.bumptech.glide.Glide;
    import com.hpplay.muiltythreaddemo.R;
    
    /**
     * Created by DON on 2016/12/30.
     */
    public class ItemPagerFragment extends Fragment {
    
        private int mDataBean;
        private ImageView imageView;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
            return View.inflate(getActivity(), R.layout.item_view_pager, null);
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            initView(view);
        }
    
    
        public void initView(View view) {
            imageView = (ImageView) view.findViewById(R.id.viewpager_item_iv);
    //        imageView.setScaleType(ImageView.ScaleType.MATRIX);
    
            Glide.with(getActivity())
                    .load(mDataBean)
                    .centerCrop()
                    .crossFade()
                    .into(imageView);
    
    
            imageView.setFocusable(false);
            imageView.setFocusableInTouchMode(false);
    
    
        }
    
        @Override
        public void setUserVisibleHint(boolean isVisibleToUser) {
            super.setUserVisibleHint(isVisibleToUser);
        }
    
        public void setData(int dataBean) {
            this.mDataBean = dataBean;
        }
    
    }
    
    

    这个类比较简单,只负责展示图片。但是如果要实现效果图中左右两张图片都要可见的效果,这里的布局文件就要稍作处理,用于显示图片的ImageView不能全屏。
    item_view_pager.xml

    <?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:orientation="vertical">
    
        <ImageView
            android:id="@+id/viewpager_item_iv"
            android:layout_width="400dp"
            android:layout_height="180dp"
            android:layout_centerInParent="true" />
    
    </RelativeLayout>
    

    ImageView的父布局是全屏的,这个是没法改变的,如果想要在一个界面中显示ViewPager的三张内容,就先需要在这里把左右两张图片的位置给预留出来,然后通过PageTransformer对左右两张图片做位移,使其能够在界面中显示出来。

    二、通过PageTransformer实现特效

    package com.hpplay.muiltythreaddemo.viewpagerdemo;
    
    import android.support.v4.view.ViewPager;
    import android.view.View;
    
    public class PageTransformer implements ViewPager.PageTransformer {
    
        /**
         * position会根据view的移动而变化  比如当前有三个view 1,2,3
         * 2在中间的时候,那么view2的position 为 0;
         * 1在左边的时候,那么view1 的position为 -1;
         * 3在右边的时候 , 那么view3的position为1;
         * <p>
         * 所以在view2移动的view3 值得变化范围就是 0---1
         * VIEW2移动的view1 值得变化范围是 0 ---  -1
         * 反之 1---0 , -1 --- 0
         *
         * @param page     移动的View对象
         * @param position 移动位置变化的值
         */
        @Override
        public void transformPage(View page, float position) {
         
            int rorate = (int) (30 + (position - 1) * 30);
            //根据position设置界面上三张图片的旋转角度,实现左右两张图片倾斜的特效
            page.setRotationY(rorate);
            float scale = (float) Math.max(1 - Math.abs(position), 0.74);
            page.setScaleX(scale);
            page.setScaleY(scale);
    
            //根据position设置界面上三张图片的偏移量,使左右两张图片也能在界面上显示
            page.setTranslationX(-1100 * position);
        }
    
    }
    

    PageTransformer的使用:viewPager.setPageTransformer(true, new PageTransformer());
    这里要特别说明,page.setTranslationX(-1100 * position)page.setScaleX(scale)page.setScaleY(scale)page.setRotationY(rorate),这四个方法的值要根据你项目的情况自己去调整大小

    三、通过反射修改ViewPager滑动速度

    package com.hpplay.muiltythreaddemo.viewpagerdemo;
    
    import android.content.Context;
    import android.view.animation.Interpolator;
    import android.widget.Scroller;
    
    public class FixedSpeedScroller extends Scroller {
        private int mDuration = 1500;
    
        public FixedSpeedScroller(Context context) {
            super(context);
        }
    
        public FixedSpeedScroller(Context context, Interpolator interpolator) {
            super(context, interpolator);
        }
    
        @Override
        public void startScroll(int startX, int startY, int dx, int dy, int duration) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }
    
        @Override
        public void startScroll(int startX, int startY, int dx, int dy) {
            // Ignore received duration, use fixed one instead
            super.startScroll(startX, startY, dx, dy, mDuration);
        }
    
        public void setmDuration(int time) {
            mDuration = time;
        }
    
        public int getmDuration() {
            return mDuration;
        }
    }
    

    使用:

           try {//调整ViewPager切换滑动速度
                Field field = ViewPager.class.getDeclaredField("mScroller");
                field.setAccessible(true);
                FixedSpeedScroller scroller = new FixedSpeedScroller(viewPager.getContext(),
                        new AccelerateInterpolator());
                field.set(viewPager, scroller);
                scroller.setmDuration(400);
            } catch (Exception e) {
            }
    

    四、控制ViewPager对连续长按遥控器左右键的事件响应

    如果不做处理,在用户按着遥控器左右键不松手的时候,ViewPager会快速切换,使界面空白。这一点是在TV APP开发中需要处理的,手机APP开发中不用处理这一点

             //控制ViewPager对连续长按遥控器左右键的事件响应
            viewPager.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (System.currentTimeMillis() - lastKeyTime < 400) {
                        return true;
                    }
    
                    if(event.getAction() == KeyEvent.ACTION_UP){
                        lastKeyTime = -1l;
                    }else{
                        lastKeyTime = System.currentTimeMillis();
                    }
                    return false;
                }
            });
    
    

    lastKeyTime为全局变量,默认-1l,private long lastKeyTime = -1l;

    相关文章

      网友评论

          本文标题:Android 一个简单的无限循环、带特效的ViewPager

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