fragment下使用ViewFlipper

  背景:广告位用ViewPager装载,但是ViewPager适合数量固定的子View,在做切换tab动态刷新数量的时候出了各种问题,例如:

java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged!

  这是出现次数最多的异常,网上虽然有各种各样的解答(主要是adapter的notifysetChange机制的问题),但是照做以后并没有任何卵用,于是准备将ViewPager直接换成ViewFlipper,关于ViewFlipper的介绍,此处不做过多说明,只讲当前项目中的具体实现

    /**
     * 给ViewFlipper装载子View
     * */
    private void startAD() {
        vfAdvertisementsFragment.removeAllViews();
        for (int i = 0; i < adList.size(); i++) {
            ImageView iv = new ImageView(context);
            iv.setImageBitmap(bitmaps.get(i));
            iv.setScaleType(ImageView.ScaleType.FIT_XY);
            vfAdvertisementsFragment.addView(iv);
        }
    }
    //开启轮播
    public void startBanner() {
        mHandler.removeCallbacks(r);
        mHandler.postDelayed(r, 3000);
    }

    //中止轮播
    public void stopBanner() {
        mHandler.removeCallbacks(r);
    }

    //轮播任务
    private void initBanner() {
        r = new Runnable() {

            @Override
            public void run() {
                showNextView();
                mHandler.postDelayed(this, 3000);
            }
        };
    }
    /**
     * 按下时停止轮播,比如滑动时不能让自动轮播任务和用户的滑动相冲
     */
    @Override
    public boolean onDown(MotionEvent e) {
        stopBanner();
        return false;
    }
    /**
     * 子View的点击事件
     */
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        Intent intent = new Intent(context, WebViewServiceActivity.class);
        intent.putExtra("title", "专题活动");
        intent.putExtra("urlAddress", adList.get(vfAdvertisementsFragment.getDisplayedChild()).srcURL);
        startActivity(intent);
        return false;
    }
    /**
     * 长按事件(注意是还未up的状态),长按不动后需要继续轮播
     */
    @Override
    public void onLongPress(MotionEvent e) {
        startBanner();
    }

    /**
     * 滑动事件,down方法停止轮播后,滑完需要继续开启轮播
     */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        boolean fling = false;
        if (e1.getX() - e2.getX() > 120) {
            showNextView();
            fling = true;
        } else if (e1.getX() - e2.getX() < -120) {
            showPreviousView();
            fling = true;
        }
        startBanner();
        return fling;
    }

    /**
     * 往前翻页,设置动画,并重置下方圆点状态,然后根据getDisplayedChild找到当前的index显示圆点
     */
    private void showPreviousView() {
        vfAdvertisementsFragment.setInAnimation(AnimationUtils.loadAnimation(context,
                R.anim.slide_right_in));
        vfAdvertisementsFragment.setOutAnimation(AnimationUtils.loadAnimation(context,
                R.anim.slide_right_out));
        vfAdvertisementsFragment.showPrevious();
        resetDot();
        dotList.get(vfAdvertisementsFragment.getDisplayedChild()).setSelected(true);
    }

    /**
     * 往后翻页,同上
     */
    private void showNextView() {
        vfAdvertisementsFragment.setInAnimation(AnimationUtils.loadAnimation(context,
                R.anim.slide_left_in));
        vfAdvertisementsFragment.setOutAnimation(AnimationUtils.loadAnimation(context,
                R.anim.slide_left_out));
        vfAdvertisementsFragment.showNext();
        resetDot();
        dotList.get(vfAdvertisementsFragment.getDisplayedChild()).setSelected(true);
    }
    /**
     * 当前fragment显示在activity顶层的时候开启轮播,否则终止轮播
     */
    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (hidden) {
            stopBanner();
        } else {
            startBanner();
        }
    }
    /**
     * activity在window顶层的时候开启轮播,onPause时终止轮播
     * */
    @Override
    public void onResume() {
        super.onResume();
        startBanner();
    }

    @Override
    public void onPause() {
        super.onPause();
        stopBanner();
    }
以上是具体实现的代码,已加上了详细的注释,主要从以下几个点入手,一步一步更改
1.轮播是否自动
2.轮播时长设为x秒,是否正常
3.子View点击事件假设进入一个新的界面,再退出,是否继续轮播
4.切换tab再切回来,是否继续轮播
5.手势滑动是否正常,与自动轮播有无冲突
6.长按是否停止轮播,后又重新开始轮播
生命周期的调用顺序是onResume→onHiddenChanged
PS:说一下以上用法的缘由,之所以将点击事件写在onSingleTapUp而不是子View的OnClickListener里面,是因为onFling方法会与点击事件OnClick冲突,网上其他人给出的方案是将dispatchTouchEvent直接交由GestureDetector来处理,这样一来导致的问题就是,切换到轮播tab的时候,你就无法再次切换了,因为tab栏组件不属于当前的fragment下,当然因具体项目的不同,可能每个人 处理方案不同,在此只是提供我的一种解决方案

你可能感兴趣的:(轮播组件)