美文网首页
viewpager+fragment实现中间大两边小无限循环带指

viewpager+fragment实现中间大两边小无限循环带指

作者: jiangbin1992 | 来源:发表于2019-07-18 17:56 被阅读0次
    • 项目需要做一个得到APP好友邀请的效果,先上咱们做的效果,如果是你需要请往下看


      微信截图_20190718174532.png
    • 就这样的效果,原理是viewpager添加5个fragment,左边显示的其实是第三个,第四个显示的是第一个,原理网上很多,没有用viewpager返回数量无限大的那种,那种耗费内存。直接上代码吧
    • activity ,新建fragment就不说了,非常简单
    public class TestViewPagerActivity extends BasesActivity {
    
        private ViewPager viewpager;
        private List<Fragment> list;
        private boolean mIsChanged = false;
        private int mCurrentPagePosition = FIRST_ITEM_INDEX;
        private static final int POINT_LENGTH = 3;
        private static final int FIRST_ITEM_INDEX = 1;
        private PointIndicator point_indicater;
    
    
        @Override
        public void initView() {
            AppTitleView appTitleView = getTitleView();
            appTitleView.initViewsVisible(true, true, false, false);
            appTitleView.setOnLeftButtonClickListener(this);
            appTitleView.setAppTitle("测试");
    
            viewpager = findViewById(R.id.viewpager);
            point_indicater = findViewById(R.id.point_indicater);
    
    
        }
    
        @Override
        public boolean isShowTitle() {
            return true;
        }
    
    
        @Override
        public void initData() {
    
            list = new ArrayList<>();
            list.add(new InviteThirdFragment());
            list.add(new InviteFirstFragment());
            list.add(new InviteSecondFragment());
            list.add(new InviteThirdFragment());
            list.add(new InviteFirstFragment());
            viewpager.setAdapter(new InviteFragmentAdapter(getSupportFragmentManager(), list));
            viewpager.setCurrentItem(1, false);
            viewpager.setOffscreenPageLimit(4);//记数从0开始!!! 设置预加载的个数
            viewpager.setPageTransformer(false, new DepthPageTransformer());
            viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageSelected(int pPosition) {
                    mIsChanged = true;
                    if (pPosition > POINT_LENGTH) {// 末位之后,跳转到首位(1)
                        mCurrentPagePosition = FIRST_ITEM_INDEX;
                    } else if (pPosition < FIRST_ITEM_INDEX) {// 首位之前,跳转到末尾(N)
                        mCurrentPagePosition = POINT_LENGTH;
                    } else {
                        mCurrentPagePosition = pPosition;
                    }
                }
    
    
                @Override
                public void onPageScrolled(int arg0, float arg1, int arg2) {
                }
    
    
                @Override
                public void onPageScrollStateChanged(int pState) {
                    if (ViewPager.SCROLL_STATE_IDLE == pState) {
                        if (mIsChanged) {
                            mIsChanged = false;
                            viewpager.setCurrentItem(mCurrentPagePosition, false);
                        }
                    }
                }
            });
            point_indicater.bindViewPager(viewpager);
        }
    
        @Override
        public int setViewLayout() {
            return R.layout.activity_testviewpager;
        }
    
        @Override
        public void onLeftButtonClick(View v) {
            finish();
        }
    
    
    }
    - 布局
    

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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:clipChildren="false"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:layout_gravity="center"
        android:layout_marginLeft="40dp"
        android:layout_marginTop="30dp"
        android:layout_marginRight="40dp"
        android:clipChildren="false"
        android:overScrollMode="never" />
    <club.modernedu.lovebook.widget.indicator.PointIndicator
        android:id="@+id/point_indicater"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="30dp"
        app:normal_color="#ffcccccc"
        app:point_size="8dp"
        app:point_space="10dp"
        app:select_color="#fffdd63b"/>
    

    </LinearLayout>

    • adapter
    
    public class InviteFragmentAdapter extends FragmentPagerAdapter {
        private List<Fragment> list;
    
        public InviteFragmentAdapter(FragmentManager fm, List<Fragment> list) {
            super(fm);
            this.list = list;
        }
    
        @Override
        public Fragment getItem(int arg0) {
            // TODO Auto-generated method stub
            return list.get(arg0);
        }
    
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return list.size();
        }
    
    
    }
    
    
    • 中间缩放的viewpager的方法
    public class DepthPageTransformer implements ViewPager.PageTransformer {
    //    private static final float MIN_SCALE = 0.70f;
    //    private static final float MIN_ALPHA = 0.5f;
    //
    //    @Override
    //    public void transformPage(View page, float position) {
    //        if (position < -1 || position > 1) {
    //            page.setAlpha(MIN_ALPHA);
    //            page.setScaleX(MIN_SCALE);
    //            page.setScaleY(MIN_SCALE);
    //        } else if (position <= 1) { // [-1,1]
    //            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
    //            if (position < 0) {
    //                float scaleX = 1 + 0.1f * position;
    //                page.setScaleX(scaleX);
    //                page.setScaleY(scaleX);
    //            } else {
    //                float scaleX = 1 - 0.1f * position;
    //                page.setScaleX(scaleX);
    //                page.setScaleY(scaleX);
    //            }
    //            page.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
    //        }
    //    }
    
        private static final float MIN_SCALE = 0.9f;
    
        @Override
        public void transformPage(View view, float position) {
            /**
             * 过滤那些 <-1 或 >1 的值,使它区于【-1,1】之间
             */
            if (position < -1) {
                position = -1;
            } else if (position > 1) {
                position = 1;
            }
            /**
             * 判断是前一页 1 + position ,右滑 pos -> -1 变 0
             * 判断是后一页 1 - position ,左滑 pos -> 1 变 0
             */
            float tempScale = position < 0 ? 1 + position : 1 - position; // [0,1]
            float scaleValue = MIN_SCALE + tempScale * 0.1f; // [0,1]
            view.setScaleX(scaleValue);
            view.setScaleY(scaleValue);
        }
    }
    
    
    • 自定义指示器PointIndicator
    /**
     * 圆点指示器
     */
    public class PointIndicator extends View implements OnPageScrollListener {
    
        private Context mContext;
    
        private int mNormalColor;
        private int mSelectColor;
        private int mPointSize;
        private int mPointSpace;
    
        private Paint mNormalPaint;
        private Paint mSelectPaint;
    
        private int mCount;
        private int enterPosition;
        private int leavePosition;
        private float percent;
    
        public PointIndicator(Context context) {
            this(context, null);
        }
    
        public PointIndicator(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PointIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initAttrs(context, attrs);
            initPaint();
        }
    
        private void initPaint() {
            mNormalPaint = new Paint();
            mNormalPaint.setColor(mNormalColor);
            mNormalPaint.setAntiAlias(true);
    
            mSelectPaint = new Paint();
            mSelectPaint.setColor(mSelectColor);
            mSelectPaint.setAntiAlias(true);
    
            mCount = 3;
        }
    
        private void initAttrs(Context context, AttributeSet attrs) {
            mContext = context;
    
            mNormalColor = 0x66cccccc;
            mSelectColor = 0xfffdd63b;
            mPointSize = dp2px(3f);
            mPointSpace = dp2px(3f);
    
            // 自定义属性
            TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.PointIndicator);
            mNormalColor = ta.getColor(R.styleable.PointIndicator_normal_color, mNormalColor);
            mSelectColor = ta.getColor(R.styleable.PointIndicator_select_color, mSelectColor);
            mPointSize = (int) ta.getDimension(R.styleable.PointIndicator_point_size, mPointSize);
            mPointSpace = (int) ta.getDimension(R.styleable.PointIndicator_point_space, mPointSpace);
            ta.recycle();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
        }
    
        private int measureWidth(int measureSpec) {
            int size = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
            switch (specMode) {
                case MeasureSpec.EXACTLY:
                    size = specSize;
                    break;
                case MeasureSpec.AT_MOST:
                case MeasureSpec.UNSPECIFIED:
                    size = mCount * mPointSize + (mCount - 1) * mPointSpace;
                    break;
            }
            return size;
        }
    
        private int measureHeight(int measureSpec) {
            int size = 0;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize = MeasureSpec.getSize(measureSpec);
            switch (specMode) {
                case MeasureSpec.EXACTLY:
                    size = specSize;
                    break;
                case MeasureSpec.AT_MOST:
                case MeasureSpec.UNSPECIFIED:
                    size = mPointSize;
                    break;
            }
            return size;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // 绘制normalPoint
            drawNormalPoint(canvas);
            // 绘制selectPoint
            drawSelectPoint(canvas);
    
        }
    
        private void drawSelectPoint(Canvas canvas) {
            float cx;
            if (enterPosition > leavePosition) {
                cx = (leavePosition + 0.5f) * mPointSize
                        + leavePosition * mPointSpace
                        + (mPointSize + mPointSpace) * percent;
            } else {
                cx = (leavePosition + 0.5f) * mPointSize
                        + leavePosition * mPointSpace
                        - (mPointSize + mPointSpace) * percent;
            }
            float cy = getHeight() / 2;
            float radius = mPointSize / 2f;
            canvas.drawCircle(cx, cy, radius, mSelectPaint);
        }
    
        private void drawNormalPoint(Canvas canvas) {
            for (int i = 0; i < mCount; i++) {
                float cx = mPointSize / 2f + (mPointSize + mPointSpace) * i;
                float cy = getHeight() / 2;
                float radius = mPointSize / 2f;
                canvas.drawCircle(cx, cy, radius, mNormalPaint);
            }
        }
    
        public void bindViewPager(ViewPager viewPager) {
            if (viewPager != null) {
                if (viewPager.getAdapter() != null) {
                    mCount = viewPager.getAdapter().getCount()-2;
                    new ViewPagerHelper().bindScrollListener(viewPager, this);
                    requestLayout(); // 绑定ViewPager后指示器重新布局,因为指示器的数量和宽度可能有变化
                }
            }
        }
    
        @Override
        public void onPageScroll(int enterPosition, int leavePosition, float percent) {
            this.enterPosition = enterPosition;
            this.leavePosition = leavePosition;
            this.percent = percent;
            postInvalidate();
        }
    
        @Override
        public void onPageSelected(int position) {
    
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
    
        }
    
        private int dp2px(float dpValue) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    dpValue,
                    mContext.getResources().getDisplayMetrics());
        }
    
    }
    
    
    • 所用到的辅助类
    /**
     * ViewPage的页面滚动监听器
     */
    public interface OnPageScrollListener {
        /**
         * 页面滚动时调用
         *
         * @param enterPosition 进入页面的位置
         * @param leavePosition 离开的页面的位置
         * @param percent       滑动百分比
         */
        void onPageScroll(int enterPosition, int leavePosition, float percent);
    
        /**
         * 页面选中时调用
         *
         * @param position 选中页面的位置
         */
        void onPageSelected(int position);
    
        /**
         * 页面滚动状态变化时调用
         *
         * @param state 页面的滚动状态
         */
        void onPageScrollStateChanged(int state);
    }
    
    /**
     * Created by XiaoJianjun on 2017/1/8.
     * ViewPager辅助类
     */
    public class ViewPagerHelper implements ViewPager.OnPageChangeListener {
    
        private double mLastPositionOffsetSum;  // 上一次滑动总的偏移量
        private OnPageScrollListener mOnPageScrollListener;
    
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            // 当前总的偏移量
            position = position - 1;
            float currentPositionOffsetSum = position + positionOffset;
            // 上次滑动的总偏移量大于此次滑动的总偏移量,页面从右向左进入(手指从右向左滑动)
            boolean rightToLeft = mLastPositionOffsetSum <= currentPositionOffsetSum;
            // 页面正在被拖动或惯性滑动
            if (currentPositionOffsetSum == mLastPositionOffsetSum) return;
            int enterPosition;
            int leavePosition;
            float percent;
            if (rightToLeft) {  // 从右向左滑
                enterPosition = (positionOffset == 0.0f) ? position : position + 1;
                leavePosition = enterPosition - 1;
                percent = (positionOffset == 0.0f) ? 1.0f : positionOffset;
                if (enterPosition == 3) {
                    return;
                }
            } else {            // 从左向右滑
                enterPosition = position;
                leavePosition = position + 1;
                percent = 1 - positionOffset;
                if (enterPosition == -1) {
                    return;
                }
            }
    
            Logger.d("enterPosition=" + enterPosition + "   leavePosition=" + leavePosition + "      percent=" + percent);
            if (mOnPageScrollListener != null) {
                mOnPageScrollListener.onPageScroll(enterPosition, leavePosition, percent);
            }
            mLastPositionOffsetSum = currentPositionOffsetSum;
        }
    
        @Override
        public void onPageSelected(int position) {
            if (mOnPageScrollListener != null) {
                mOnPageScrollListener.onPageSelected(position);
            }
        }
    
        /**
         * @param state 当前滑动状态
         *              ViewPager.SCROLL_STATE_IDLE     页面处于闲置、稳定状态,即没被拖动也没惯性滑动
         *              ViewPager.SCROLL_STATE_DRAGGING 页面正在被用户拖动,即手指正在拖动状态
         *              Viewpager.SCROLL_STATE_SETTLING 页面处于即将到达最终状态的过程,即手指松开后惯性滑动状态
         */
        @Override
        public void onPageScrollStateChanged(int state) {
            if (mOnPageScrollListener != null) {
                mOnPageScrollListener.onPageScrollStateChanged(state);
            }
        }
    
        public void bindScrollListener(ViewPager viewPager, OnPageScrollListener onPageScrollListener) {
            mOnPageScrollListener = onPageScrollListener;
            viewPager.addOnPageChangeListener(this);
        }
    }
    
    
    • 就这几个类,原理网上一大堆就不细述了,需要注意的事设置adapter的顺序,先设置adapter在设置属性才行

    相关文章

      网友评论

          本文标题:viewpager+fragment实现中间大两边小无限循环带指

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