修改ViewPage的r预加载,左右滑动,切换经过中间页问题,ViewPager一屏显示多张图片

2017-04-16 19:40:01
1.屏蔽切换的时候需要经过中间页
2.屏蔽ViewPager的滑动
3.预加载问题

复制代码

import android.content.Context;import android.support.v4.view.ViewPager;import android.util.AttributeSet;import android.view.MotionEvent;/**
 * 1.屏蔽切换的时候需要经过中间页
 * 2.屏蔽ViewPager的滑动
 * 3.预加载问题 */public class MyViewPager extends ViewPager {    /**
     * 是否可以滑动     */
    private boolean isCanScroll = false;    public MyViewPager(Context context) {        super(context);
    }    public MyViewPager(Context context, AttributeSet attrs) {        super(context, attrs);
    }    /**
     * 解决切换需要经过中间页     */
    @Override    public void setCurrentItem(int item) {        //super.setCurrentItem(item);源码
        super.setCurrentItem(item,false);//false表示切换的时候,不经过两个页面的中间页    }    /**
     * 让ViewPager不能左右滑动     */
    @Override    public boolean onTouchEvent(MotionEvent ev) {        if(isCanScroll){            return super.onTouchEvent(ev);
        }else{            return false;
        }
    }    /**
     * 暴露出去的方法,屏蔽ViewPager的滑动,默认不可滑动
     * @param isCanScroll 为true可以左右滑动,为false不可滑动     */
    public void setIsCanScroll(boolean isCanScroll){        this.isCanScroll = isCanScroll;
    }

    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if(isCanScroll){            return super.onInterceptTouchEvent(ev);
        }else{            return false;
        }
    }    /* 设置预加载页数的源码,默认为1,当设置的数大于1是有效的,小于1就无效了
       1)如果想预加载多页(默认预加载一页),可以使用setOffscreenPageLimit(int limit),意思为幕后页的限制,默认为1
       2)当你不想要预加载的时候,那是不是只需要将这个值设为0呢?答案是不行的,
      解决办法:复制ViewPager源码将DEFAULT_OFFSCREEN_PAGES这个值改为0就可以了
    public void setOffscreenPageLimit(int limit) {
        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            limit = DEFAULT_OFFSCREEN_PAGES;//可见当设置的值小于1时无效
        }
        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }     */}

复制代码

但是切记,复制ViewPager源码别复制高版本的,防止出问题,因为现在Android都7.0了,版本都老高了,其实android虽然每个版本都有v4包,但是这些v4包是有差异的。这就造成高版本v4包里的ViewPager,即使你Copy它,将其DEFAULT_OFFSCREEN_PAGES的值改为0,还是不起作用的,其中的逻辑变了。具体哪里变了导致无效我也没有继续研究了,下面给出一份低版本修改好的(只修改了预加载)

 View Code

2.利用ViewPager实现一屏显示多张图片的问题

MainActivity代码:

复制代码

public class MainActivity extends AppCompatActivity {    private List<ImageView> list;    private int[] imgsId={R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d};

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
        initData();
        viewPager.setAdapter(new MyPagerAdapter(list));
    }    
    //初始化显示的图片
    private void initData() {
        list = new ArrayList<>();        for (int i : imgsId) {
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setImageResource(i);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            list.add(imageView);
        }
    }
}

复制代码

适配器:

复制代码

public class MyPagerAdapter extends PagerAdapter {    private List<ImageView> list;    public MyPagerAdapter(List<ImageView> list) {        this.list = list;
    }

    @Override    public int getCount() {        return list.size();
    }

    @Override    public boolean isViewFromObject(View view, Object object) {        return view == object;
    }

    @Override    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(list.get(position));        return list.get(position);
    }

    @Override    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
        object = null;
    }    /**
     * 设置该页内容所占屏幕的宽度     */
    @Override    public float getPageWidth(int position) {        //return 1.f; 默认返回1,代表该position占据了ViewPager的一整页,范围(0,1]
        return 0.8f;
    }
}

复制代码

布局文件:

 View Code

效果如下: 如果没重写getPageWidth()方法(左图)              重写后为(右图)

下面看下一屏显示多张图片的具体实现:

由于上面适配器中的getPageWidth方法只能控制一边的距离,不能实现左右两边显示,所以改功能需要删除上面适配器中的getPageWidth()方法

java代码:

复制代码

import android.os.Bundle;import android.support.v4.view.ViewPager;import android.support.v7.app.AppCompatActivity;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;import android.widget.LinearLayout;import java.util.ArrayList;import java.util.List;/**
 * ViewPager显示多张图片 */public class MainActivity extends AppCompatActivity {    private List<ImageView> list;    private int[] imgsId={R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d};

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();//初始化数据        //ViewPager的父布局
        final LinearLayout viewPagerContainer  = (LinearLayout) findViewById(R.id.viewPager_layout);        final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
        viewPager.setOffscreenPageLimit(3); // viewPager的缓存页数
        viewPager.setPageMargin(30); // 设置各页面的间距        // 将父节点Layout事件分发给viewpager,否则只能滑动中间的一个view对象
        viewPagerContainer.setOnTouchListener(new View.OnTouchListener() {
            @Override            public boolean onTouch(View v, MotionEvent event) {                return viewPager.dispatchTouchEvent(event);
            }
        });        //设置ViewPager的滑动监听,必须在滑动的时候刷新界面才能看到效果
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {                //必须刷新页面,才能看到效果
                if (viewPagerContainer != null) {
                    viewPagerContainer.invalidate();
                }
            }

            @Override            public void onPageSelected(int position) {

            }

            @Override            public void onPageScrollStateChanged(int state) {

            }
        });        //设置适配器
        viewPager.setAdapter(new MyPagerAdapter(list));
    }    //初始化显示的图片
    private void initData() {
        list = new ArrayList<>();        for (int i : imgsId) {
            ImageView imageView = new ImageView(MainActivity.this);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            imageView.setImageResource(i);
            list.add(imageView);
        }
    }
}

复制代码

布局文件:

复制代码

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/viewPager_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:layerType="software"
    android:clipChildren="false">

    <!--
        一屏显示多张图片的步骤:
        1.配置ViewPager和其父布局的 android:clipChildren属性为”false”.
            (android:clipChildren表示是否限制子View在其范围内,默认为true. 代码设置setClipChildren(false))
            因为如果clipChildren属性设置为true,就表明我们要将children给clip掉,
            就是说对于子元素来说,超出当前view的部分都会被切掉,那我们在这里把它设置成false,
            就表明超出view的部分,不要切掉,依然显示。

        2.设置ViewPager的父布局,android:layerType="software",这样才能显示左右两边的图片,否则不显示为空白

        3.设置幕后item的缓存数目。如果一屏展示的pager数目多的话就需要设置此项。
            viewPager.setOffscreenPageLimit(3); //具体缓存页数看需求

        4.设置页与页之间的间距
            viewPager.setPageMargin(int marginPixls);// setPageMargin表示设置page之间的间距

        5.将ViewPager的父布局触摸事件分发给viewpager,否则只能滑动ViewPager中间的那个view对象

        6.必须在ViewPager的滑动监听中刷新界面才能看到效果
        
        具体代码见MainActivity的onCreate方法两空行之间的代码     -->

    <!--android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"代表居中显示的pager距离屏幕左右两边的距离-->
    <android.support.v4.view.ViewPager        android:id="@+id/viewPager"
        android:clipChildren="false"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:layout_width="match_parent"
        android:layout_height="300dp">
    </android.support.v4.view.ViewPager></LinearLayout>

复制代码

效果如下:

 如果需要切换效果可以看鸿洋大神的:   巧用ViewPager 打造不一样的广告轮播切换效果

https://github.com/hongyangAndroid/MagicViewPager


  • 2018-11-17 21:05:48

    Android ANR发生的原因总结和解决办法

    ANR的全称是application not responding,是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。

  • 2018-11-17 21:08:09

    Android 单个应用的内存限制

    获取Android手机应用内存大小 手机不同其性能也不同,手机本身内存可能有大有小,所以针对每个应用的内存大小也不相同。

  • 2018-11-17 21:11:14

    Android中App可分配内存的大小

     结果:(1)未设定属性android:largeheap = "true"时,可以申请到的最大内存空间为221M。      (2)设定属性android:largeheap = "true"时, 可以申请的最大内存空间为478M,是原来的两倍多一些。

  • 2018-11-17 22:44:53

    LeakCanary,30分钟从入门到精通

    在性能优化中,内存是一个不得不聊的话题;然而内存泄漏,显示已经成为内存优化的一个重量级的方向。当前流行的内存泄漏分析工具中,不得不提的就是LeakCanary框架;这是一个集成方便, 使用便捷,配置超级简单的框架,实现的功能却是极为强大的。

  • 2018-11-17 22:53:01

    gc for alloc freed

    在数组中选择图片然后显示,然后。。。logcat不断显示GC回收。最后程序黑屏。

  • 2018-11-17 23:25:38

    Android高效内存1:一张图片占用多少内存

    在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用。而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果。本文就简单介绍一张图片到底占用多少内存,我们先假设我们有一张图片时 600 * 800 的,图片占用空间大小假设是 100KB。另外本文知识点也是面试官喜欢问的一个点,看看自己的回答到什么级别了。

  • 2018-11-18 09:06:06

    Android子线程中更新UI的3种方法

    UI的更新必须在主线程中完成,所以不管上述那种方法,都是将更新UI的消息发送到了主线程的消息对象,让主线程做处理。

  • 2018-11-19 15:10:23

    nodemailer的使用,nodejs发送邮件

    前段时间有个很普通的项目需要发邮件的功能,而且是刚开始学nodejs,所以只是搜索了下用什么好的库能实现,就找到了nodemailer了。这篇文章主要是记录一下使用的过程和经验。