ViewPager+Fragment取消预加载以及禁止滑动

2017-04-15 23:54:49

取消预加载

网上了解了很多取消预加载的方法,里面提到了使用一个viewpager的public方法setOffscreenPageLimit 经过查看源码以及验证发现该方法是管理Viewpager预加载的页数,最低也是默认为一页(例如ViewPager一共有4页,当前手机屏幕显示第一页,那么第二页已经被缓存了)。如果你想多缓存几页可以通过该方法进行设置;所以想要完全取消预加载(一页都不缓存,只加载当前页),通过这个方法是行不通的(通过其他的方法能不能行就不知道了)。

但是在细想之后发现我们取消预加载大多无非是取消掉我们放在这个fragment中的异步操作(我的是放在OnCreate或者OnCreateView方法里加载数据源的),那我们把这个异步操作的方法提取出来,然后在这个fragment的view每次显示的时候调用,不就达到了取消预加载的效果了。所以Fragment的public方法setUserVisibleHint (设置fragment的可见状态)恰好是我们所需要的,我们可以重写他然后在里面获取到fragment的显示状态实现我们的方法回调,这样就大功告成了,下面给出我写的几个重要类以及方法原型。

  • 以下是重写setUserVisibleHint方法的基础类,在用到Fragment的时候继承该类然后将你的异步加载操作方法放入相应的回调方法就能够实现需要的效果:

public abstract class BaseFragment extends Fragment {
    /** Fragment当前状态是否可见 */
    protected boolean isVisible;    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }    /**
     * 可见时的回调方法
     */
    protected abstract void onVisible();    /**
     * 不可见时的回调方法
     */
    protected abstract void onInvisible();
}123456789101112131415161718192021222324252627
  • 以下是setOffscreenPageLimit方法原型(里面的常量DEFAULT_OFFSCREEN_PAGES为整形1):

/**
     * Set the number of pages that should be retained to either side of the
     * current page in the view hierarchy in an idle state. Pages beyond this
     * limit will be recreated from the adapter when needed.
     *
     * <p>This is offered as an optimization. If you know in advance the number
     * of pages you will need to support or have lazy-loading mechanisms in place
     * on your pages, tweaking this setting can have benefits in perceived smoothness
     * of paging animations and interaction. If you have a small number of pages (3-4)
     * that you can keep active all at once, less time will be spent in layout for
     * newly created view subtrees as the user pages back and forth.</p>
     *
     * <p>You should keep this limit low, especially if your pages have complex layouts.
     * This setting defaults to 1.</p>
     *
     * @param limit How many pages will be kept offscreen in an idle state.
     */
    public void setOffscreenPageLimit(int limit) {        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                    DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }12345678910111213141516171819202122232425262728
  • 以下是setUserVisibleHint方法的原型

/**
     * Set a hint to the system about whether this fragment's UI is currently visible
     * to the user. This hint defaults to true and is persistent across fragment instance
     * state save and restore.
     *
     * <p>An app may set this to false to indicate that the fragment's UI is
     * scrolled out of visibility or is otherwise not directly visible to the user.
     * This may be used by the system to prioritize operations such as fragment lifecycle updates
     * or loader ordering behavior.</p>
     *
     * @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
     *                        false if it is not.
     */
    public void setUserVisibleHint(boolean isVisibleToUser) {        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
            mFragmentManager.performPendingDeferredStart(this);
        }
        mUserVisibleHint = isVisibleToUser;
        mDeferStart = !isVisibleToUser;
    }1234567891011121314151617181920

小结一下:取消预加载不需要任何额外的ViewPager属性配置操作,只需要在构建类Fragment的时候继承BaseFragment实现两个抽象方法,然后将异步操作方法放入相应的回调方法即可。

禁止滑动

在布局中引用以下重写的ViewPager CustomViewPager 类,然后再调用其中的public方法setScanScroll 设置(如在Activity的onCreate方法中:

CustomViewPager viewPager = (CustomViewPager) findViewById(R.id.viewpager);viewPager.setScanScroll(false);12

)调用即可。 
以下给出重要的类以及重要注释。

public class CustomViewPager extends ViewPager {

    private boolean isCanScroll = true;    public CustomViewPager(Context context) {        super(context);
    }    public CustomViewPager(Context context, AttributeSet attrs) {        super(context, attrs);
    }    /**
     * 设置其是否能滑动换页
     * @param isCanScroll false 不能换页, true 可以滑动换页
     */
    public void setScanScroll(boolean isCanScroll) {        this.isCanScroll = isCanScroll;
    }    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {        return isCanScroll && super.onInterceptTouchEvent(ev);
    }    @Override
    public boolean onTouchEvent(MotionEvent ev) {        return isCanScroll && super.onTouchEvent(ev);

    }
}1234567891011121314151617181920212223242526272829303132

方法onInterceptTouchEvent API注释:

android.support.v4.view.ViewPager
public boolean onInterceptTouchEvent(@NotNull MotionEvent ev)
Description copied from class: ViewGroup Implement this method to intercept all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point.

实现此方法可拦截所有触摸屏幕事件。这允许您监听事件传递给你的子类,并且在任何点取得当前手势的所有权。

Using this function takes some care, as it has a fairly complicated interaction with View.onTouchEvent(MotionEvent), and using it requires implementing that method as well as this one in the correct way. Events will be received in the following order:
You will receive the down event here.
The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
If you return true from here, you will not receive any following events: the target view will receive the same event but with the action MotionEvent.ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.
Overrides:
onInterceptTouchEvent in class ViewGroup
Parameters:
ev - The motion event being dispatched down the hierarchy.
Returns:
Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent(). The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here.

从子类中拦截到移动事件并将事件传递到了ViewGroup则返回true


  • 2020-12-13 20:15:43

    解决gitlab限制上传文件大小的问题

    服务端的限制有两个地方一个是gitlab本身,另外一个是gitlab使用的nginx。 gitlab本身也是很好解决的,使用管理员用户登录gitlab在设置Account and limit中加大Maximum attachment size (MB)和Maximum push size (MB)即可解决 nginx的话修改gitlab.rb这个文件中

  • 2020-12-14 15:06:50

    youtube-dl视频下载神器

    youtube-dl 是一款命令行下的视频下载工具,看着名称像是 YouTube 下载工具,其实这款工具不仅支持 YouTube ,还支持非常多的视频网站,比如优酷、爱奇艺、 bilibili 等,在写这篇日志的时候,暂时不支持腾讯视频。

  • 2020-12-15 20:06:43

    更多WebTorrent例子

    WebTorrent是第一个运行在浏览器的Torrent客户端。是的,没错。就是浏览器! 它完全是用JavaScript编写的,并使用WebRTC实现了真正的点对点传输。不需要浏览器插件、扩展或安装。 使用开放的Web标准,WebTorrent将网站用户连接在一起,形成一个分布式的、分散的Browser-to-browser网络,以实现高效的文件传输。

  • 2020-12-16 06:43:06

    WebRTC 实现Android点到点互连(含Demo)

    WebRTC被誉为是web长期开源开发的一个新启元,是近年来web开发的最重要创新。WebRTC允许Web开发者在其web应用中添加视频聊天或者点对点数据传输,不需要复杂的代码或者昂贵的配置。目前支持Chrome、Firefox和Opera,后续会支持更多的浏览器,它有能力达到数十亿的设备。

  • 2020-12-16 22:04:03

    基于本地代理的边下边播技术分析

    我们熟知的边下边播技术,是迅雷提供的,还有之前的快播、快车等工具,它们使用的技术基本上都是P2P下载技术。 P2P下载技术,本质上它并不是C-S的架构,P2P----> Peer to Peer,实际上它将各个客户端的资源调度起来,给上传资源种子,方便后续的下载者可以快速有效的下载资源,这种方式需要服务器整合各个Client,在有用户需要下载的情况下,服务器能及时调度资源,开始给下载者提供资源信息,保证下载者下载资源越快越好。P2P的下载方式后面我们专门介绍一下。这儿不继续展开了。