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下,当然因具体项目的不同,可能每个人 处理方案不同,在此只是提供我的一种解决方案

可以使用计数器变量来记录当前切换的次数,当切换到第三次时,停止自动切换。具体实现方法如下: 1. 在Activity或Fragment定义计数器变量: ```java private int flipCount = 0; ``` 2. 在ViewFlipper设置自动切换和时间间隔: ```xml <ViewFlipper android:id="@+id/flipper" android:layout_width="match_parent" android:layout_height="wrap_content" android:autoStart="true" android:flipInterval="2000"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="View 1" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="View 2" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="View 3" /> </ViewFlipper> ``` 3. 在Activity或Fragment获取ViewFlipper对象,并设置自动切换监听器: ```java ViewFlipper flipper = findViewById(R.id.flipper); flipper.setAutoStart(true); flipper.setFlipInterval(2000); flipper.startFlipping(); flipper.setInAnimation(this, android.R.anim.slide_in_left); flipper.setOutAnimation(this, android.R.anim.slide_out_right); flipper.setInAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { flipCount++; // 计数器加1 if (flipCount >= 3) { flipper.stopFlipping(); // 切换到第三次时停止自动切换 } } @Override public void onAnimationRepeat(Animation animation) { } }); ``` 在以上代码,通过setInAnimationListener()方法设置了ViewFlipper的进入动画监听器,当动画结束时,计数器加1。当计数器达到3时,调用stopFlipping()方法停止自动切换。这样就实现了只让ViewFlipper自动切换三次的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值