ViewPager图片轮播小练习

1. 图片轮播

学习资料:

十分感谢两位同学

两个同学的思路大同小异,都没有采用将getCount()设置Integer.MAX_VALUE的常规思路,采用原理是基本是一致的,看懂一个,另外一个自然也就懂了


原理

ViewPageritem队列中,首先添加原队尾,也就是5;然后再添加原队首1,最终比实际item多出两个

原理图也直接拿来用了,我实际用坚果手机测试,这种方式带来的优化效果比设置 Integer.MAX_VALUE 方式几乎可以忽略。占用内存相差不大,使用这种方式,循环多次时,占用内存增长速度感觉稍微慢一点点。个人感觉,性能方面两种方式基本是一样的。但这种方式,更符合真正的循环轮播吧


1.1 BannerAdapter

主要是startUpdate()方法的重写

public class BannerAdapter extends PagerAdapter {
    private List<String> imageViews = new ArrayList<>();
    private int bannerSize;

    @Override
    public int getCount() {
        bannerSize = imageViews.size();
        return bannerSize;
    }

    public void setImageViews(List<String> imageViews) {
        this.imageViews.addAll(imageViews);
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView imageView = new ImageView(container.getContext());
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        String url = imageViews.get(position);
        Glide.with(container.getContext()).load(url).into(imageView);
        container.addView(imageView);
        return imageView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    @Override
    public void startUpdate(ViewGroup container) {
        ViewPager vp = (ViewPager) container;
        int position = vp.getCurrentItem();
        if (position == 0) {
            position = bannerSize - 2;
            vp.setCurrentItem(position, false);
        } else if (position == (bannerSize - 1)) {
            position = 1;
            vp.setCurrentItem(position, false);
        }
    }
}

startUpdate()方法中,根据滑动到的当前的position来确定最终的CurrentItem。当position0时,就设置CurrentItem为原队尾;当positon为新队列的最后时,就设置CurrentItem1

vp.setCurrentItem(position, false)中第2个参数,是去除动画效果


1.2 Activity


运行效果

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false">

    <android.support.v4.view.ViewPager
        android:id="@+id/banner_activity_vp"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:layout_centerInParent="true"
        android:layout_marginLeft="30dp"
        android:layout_marginRight="30dp"
        android:clipChildren="false" />
</RelativeLayout>

RelativeLayoutViewPager的布局中都使用,android:clipChildren="false",主要是为了让ViewPager一屏幕可以显示多个item,显示多少则由android:layout_marginLeft这个系列的属性控制


Activity代码:

public class BannerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_banner);
        initView();
    }

    private void initView() {
        List<String> imageViews = new ArrayList<>();
        imageViews.add(Urls.IMG_URL3);//添加队尾
        imageViews.add(Urls.IMG_URL1);
        imageViews.add(Urls.IMG_URL2);
        imageViews.add(Urls.IMG_URL3);
        imageViews.add(Urls.IMG_URL1);//添加队首

        ViewPager vp = (ViewPager) findViewById(R.id.banner_activity_vp);
        BannerAdapter adapter = new BannerAdapter();
        vp.setPageMargin(10);
        adapter.setImageViews(imageViews);
        vp.setOffscreenPageLimit(3);
        vp.setAdapter(adapter);
        vp.setCurrentItem(1);//显示img_url_1
    }
}

imageViews中,多添加了两个img_url,由于添加了一个新的队首,设置vp.setCurrentItem(1)


2. 切换动画

学习资料


切换动画

2.1 BannerTransformer

public class BannerTransformer implements ViewPager.PageTransformer {
    private static final float MAX_SCALE = 1.0f;
    private static final float MIN_SCALE = 0.8f;

    @Override
    public void transformPage(View page, float position) {
        if (position < -1) {//(-Infinity,-1)
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
        } else if (position <= 0) {//[-1,0]
            float scaleFactor =  MIN_SCALE+(1-Math.abs(position))*(MAX_SCALE-MIN_SCALE);
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
        } else if (position <= 1) {//(0,1]
            float scaleFactor =  MIN_SCALE+(1-Math.abs(position))*(MAX_SCALE-MIN_SCALE);
            page.setScaleX(scaleFactor);
            page.setScaleY(scaleFactor);
        } else {//(1,Infinity)
            page.setScaleX(MIN_SCALE);
            page.setScaleY(MIN_SCALE);
        }
    }
}

切换动画使用vp.setPageTransformer(true, new BannerTransformer())

动画就涉及到了一个缩放效果

一个page的position为0代表它处于中间,为1代表它完全处于右边,为-1代表它完全处于左边

page_a切换到page_bpage_a0.0f --> -1.0f,而page_b1.0f --> 0.0f


2.2 问题

遇到一个坑,查了一个多小时,暂时也没有考虑出到底啥原因

一开始在BannerAdapter中,重写的是finshUpdate(),右滑没有问题,左滑遇到一个问题


遇到问题

手指从右侧向左滑时,3个page每循环一次后,就会出现问题,左面的page会闪一下,然后大小变成原始的正常大小,设置的缩放效果无效

BannerAdapter中的finshUpdate()改为startUpdata()方法后,就好了

若使用设置Integer.MAX_VALUE的方式,使用同一个切换动画,没有任何问题。

public class Touch extends Activity implements OnTouchListener, OnClickListener { private static final String TAG = "Touch" ; // These matrices will be used to move and zoom image Matrix matrix = new Matrix(); Matrix savedMatrix = new Matrix(); PointF start = new PointF(); PointF mid = new PointF(); float oldDist; private ImageView view; private Button zoomIn, zoomOut; //button zoom private float scaleWidth = 1; private float scaleHeight = 1; private Bitmap bmp, zoomedBMP; private int zoom_level = 0; private static final double ZOOM_IN_SCALE = 1.25;//放大系数 private static final double ZOOM_OUT_SCALE = 0.8;//缩小系数 // We can be in one of these 3 states static final int NONE = 0; static final int DRAG = 1; static final int ZOOM = 2; int mode = NONE; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //放大按钮 zoomIn = (Button) findViewById(R.id.zoom_in); //缩小按钮 zoomOut = (Button) findViewById(R.id.zoom_out); zoomIn.setOnClickListener(this); zoomOut.setOnClickListener(this); view = (ImageView) findViewById(R.id.imageView); view.setOnTouchListener(this); //取得drawable中图片,放大,缩小,多点触摸的作用对象 bmp = BitmapFactory.decodeResource(Touch.this.getResources(), R.drawable.butterfly); } public boolean onTouch(View v, MotionEvent event) { // Handle touch events here... ImageView view = (ImageView) v; // Handle touch events here... switch (event.getAction() & MotionEvent.ACTION_MASK) { //设置拖拉模式 case MotionEvent.ACTION_DOWN: savedMatrix.set(matrix); start.set(event.getX(), event.getY()); Log.d(TAG, "mode=DRAG" ); mode = DRAG; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = NONE; Log.d(TAG, "mode=NONE" ); break; //设置多点触摸模式 case MotionEvent.ACTION_POINTER_DOWN: oldDist = spacing(event); Log.d(TAG, "oldDist=" + oldDist); if (oldDist > 10f) { savedMatrix.set(matrix); midPoint(mid, event); mode = ZOOM; Log.d(TAG, "mode=ZOOM" ); } break; //若为DRAG模式,则点击移动图片 case MotionEvent.ACTION_MOVE: if (mode == DRAG) { matrix.set(savedMatrix); // 设置位移 matrix.postTranslate(event.getX() - start.x, event.getX() - start.x); } //若为ZOOM模式,则多点触摸缩放 else if (mode == ZOOM) { float newDist = spacing(event); Log.d(TAG, "newDist=" + newDist); if (newDist > 10f) { matrix.set(savedMatrix); float scale = newDist / oldDist; //设置缩放比例和图片中点位置 matrix.postScale(scale, scale, mid.x, mid.y); } } break; } // Perform the transformation view.setImageMatrix(matrix); return true; // indicate event was handled } //计算移动距离 private float spacing(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return FloatMath.sqrt(x * x + y * y); } //计算中点位置 private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } //放大,缩小按钮点击事件 @Override public void onClick(View v) { if(v == zoomIn){ enlarge(); }else if (v == zoomOut) { small(); } } //按钮点击缩小函数 private void small() { int bmpWidth = bmp.getWidth(); int bmpHeight = bmp.getHeight(); scaleWidth = (float) (scaleWidth * ZOOM_OUT_SCALE); scaleHeight = (float) (scaleHeight * ZOOM_OUT_SCALE); Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); zoomedBMP = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, true); view.setImageBitmap(zoomedBMP); } //按钮点击放大函数 private void enlarge() { try { int bmpWidth = bmp.getWidth(); int bmpHeight = bmp.getHeight(); scaleWidth = (float) (scaleWidth * ZOOM_IN_SCALE); scaleHeight = (float) (scaleHeight * ZOOM_IN_SCALE); Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); zoomedBMP = Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, true); view.setImageBitmap(zoomedBMP); } catch (Exception e) { //can't zoom because of memory issue, just ignore, no big deal
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值