画廊效果的ViewPager实现(附带无限自动轮播)[通俗易懂]

画廊效果的ViewPager实现(附带无限自动轮播)[通俗易懂]废话不多说,先上效果图根据效果所示,第一步实现适配器,完成无限循环首先做数据上的处理publicstaticclassLoopViewPagerAdapterextendsPagerAdapter{ …..LoopViewPagerAdapter(Contextcontext,ArrayList<Integer>imgIds){…

大家好,又见面了,我是你们的朋友全栈君。

废话不多说,先上效果图

画廊效果的ViewPager

根据效果所示,第一步实现适配器,完成无限循环

首先做数据上的处理

  public static class LoopViewPagerAdapter extends PagerAdapter{
  	.....
    LoopViewPagerAdapter(Context context, ArrayList<Integer> imgIds){
      this.context = context;

      this.ids.add(imgIds.get(imgIds.size()-1)); 将原本的最后一页复制一份放到第一页
      this.ids.addAll(imgIds);
      this.ids.add(imgIds.get(0)); 将原本的第一页复制一份放到最后一页

      views = new View[ids.size()];
    }
    .....
 }

配合OnPageChangeListener 即可实现无限循环

 private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {

    @Override
    public void onPageSelected(int position) {
      LogUtils.d("LoopViewPager onPageSelected --> " + loopViewPagerAdapter.getCount() + " : " + position);
      if (position == 0){
      	// 滑动到第一页的时候直接跳到倒数第二页,因为两页内容完全一致,跳的过程不会被人眼捕捉到
        setCurrentItem(loopViewPagerAdapter.getCount() - 2, false);
      }
      if (position == loopViewPagerAdapter.getCount() - 1){
      	// 同理滑动到倒数第一页的时候直接跳到第二页
        setCurrentItem(1, false);
      }
    }
    ...
}

第二步 实现放大效果

借助OnPageChangeListener 的 onPageScrolled 滑动进度给指定的Item放大和缩小

private static final float BASE_SCALE = 0.9f; // 为方便调整放大幅度,设立的最小倍数
private static final float BASE_INCREMENT = 0.2f; // 最大放大倍数与最小放大倍数的差值
private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
	...
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
      float zoom = BASE_SCALE + (BASE_INCREMENT - Math.abs(positionOffset * BASE_INCREMENT));
      loopViewPagerAdapter.getViews(position).setScaleX(zoom);
      loopViewPagerAdapter.getViews(position).setScaleY(zoom);

      if (positionOffset > 0) {
        // 左滑,右侧放大
        View leftView = loopViewPagerAdapter.getViews(position + 1);
        if (leftView != null){
          float zoomNext = BASE_SCALE + Math.abs(positionOffset * BASE_INCREMENT);
          leftView.setScaleX(zoomNext);
          leftView.setScaleY(zoomNext);
        }
      }
      if (positionOffset < 0) {
        // 右滑,左侧放大
        View rightView = loopViewPagerAdapter.getViews(position - 1);
        if (rightView != null){
          float zoomNext = BASE_SCALE + Math.abs(positionOffset * BASE_INCREMENT);
          rightView.setScaleX(zoomNext);
          rightView.setScaleY(zoomNext);
        }
    }

	@Override
    public void onPageScrollStateChanged(int state) {
      LogUtils.d("LoopViewPager onPageScrollStateChanged --> " + state);
      if (state == 0) {
        int position = getCurrentItem();
        for (int i = 0; i < loopViewPagerAdapter.getViews().length; i++) {
          View itemView = loopViewPagerAdapter.getViews(i);
          if (itemView != null){
            if (i == position){
              loopViewPagerAdapter.getViews(i).setScaleX(BASE_SCALE + BASE_INCREMENT);
              loopViewPagerAdapter.getViews(i).setScaleY(BASE_SCALE + BASE_INCREMENT);
            }else {
              loopViewPagerAdapter.getViews(i).setScaleX(BASE_SCALE);
              loopViewPagerAdapter.getViews(i).setScaleY(BASE_SCALE);
            }
          }
        }
      }
    }
 }

第三步 增加自动轮播功能

  @SuppressLint("HandlerLeak")
  private class MyHandler extends Handler {

    WeakReference<Context> mWeakReference;

    MyHandler(Context context) {
      mWeakReference = new WeakReference<>(context);
    }

    @Override
    public void handleMessage(Message msg) {
      Context context = mWeakReference.get();
      if (context == null) {
        return;
      }
      if (msg.what == HANDLE_LOOP_MSG) {
        int curItem = getCurrentItem() + 1;
        setCurrentItem(curItem);
      }
      if (isAutoLoop.get()){
        mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
      }
    }
  }

 // 开始自动轮播
 MyHandler mHandler = new MyHandler(getContext());
 mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);

大功告成,附上完整代码

package com.zhlm.babyhearread.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.zhlm.babyhearread.base.utils.LogUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 自动轮播ViewPager,画廊效果(当前展示的放大,两侧待展示的缩小),两侧可看到部分
 * 目前仅支持使用图片,需要其他的话请自行将PagerAdapter改造成FragmentPagerAdapter
 *
 * 使用方法
 * <xxx.xxx.LoopViewPager
 *     android:id="@+id/loopViewPager"
 *     android:layout_width="match_parent"
 *     android:layout_height="wrap_content"
 *     android:paddingStart="40dp"
 *     android:paddingEnd="40dp"
 *     android:clipToPadding="false"
 *     />
 *
 * ArrayList<Integer> ids = new ArrayList<>();
 * ids.add(R.drawable.img1);
 * ids.add(R.drawable.img2);
 * ids.add(R.drawable.img3);
 * ids.add(R.drawable.img4);
 * LoopViewPager loopViewPager = findViewById(R.id.loopViewPager);
 * loopViewPager.setDates(ids); // 设置数据
 * loopViewPager.autoLoop(true); // 自动轮播
 *
 * author liming  2019/12/9 16:40
 * e-mail : limit_round@163.com
 *
 */
public class LoopViewPager extends ViewPager {

  private MyHandler mHandler;
  private LoopViewPagerAdapter loopViewPagerAdapter;
  private final static int HANDLE_LOOP_MSG = 101;
  private AtomicBoolean isAutoLoop = new AtomicBoolean();

  private static final float BASE_SCALE = 0.9f;
  private static final float BASE_INCREMENT = 0.2f;

  public LoopViewPager(Context context) {
    this(context, null);
  }

  public LoopViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  public void autoLoop(boolean isAuto) {
    if (mHandler == null) {
      mHandler = new MyHandler(getContext());
    }
    if (isAuto) {
      mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
    } else {
      mHandler.removeCallbacksAndMessages(null);
    }
    isAutoLoop.set(isAuto);
  }

  public void setDates(ArrayList<Integer> imgIds){
    setOffscreenPageLimit(5);
    loopViewPagerAdapter = new LoopViewPagerAdapter(getContext(), imgIds);
    loopViewPagerAdapter.initItem();
    setAdapter(loopViewPagerAdapter);
    setCurrentItem(1);

    setOnPageChangeListener(onPageChangeListener);
  }

  private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {

    @Override
    public void onPageSelected(int position) {
      LogUtils.d("LoopViewPager onPageSelected --> " + loopViewPagerAdapter.getCount() + " : " + position);
      if (position == 0){
        setCurrentItem(loopViewPagerAdapter.getCount() - 2, false);
      }
      if (position == loopViewPagerAdapter.getCount() - 1){
        setCurrentItem(1, false);
      }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
      float zoom = BASE_SCALE + (BASE_INCREMENT - Math.abs(positionOffset * BASE_INCREMENT));
      loopViewPagerAdapter.getViews(position).setScaleX(zoom);
      loopViewPagerAdapter.getViews(position).setScaleY(zoom);

      if (positionOffset > 0) {
        // 左滑,右侧放大
        View leftView = loopViewPagerAdapter.getViews(position + 1);
        if (leftView != null){
          float zoomNext = BASE_SCALE + Math.abs(positionOffset * BASE_INCREMENT);
          leftView.setScaleX(zoomNext);
          leftView.setScaleY(zoomNext);
        }
      }
      if (positionOffset < 0) {
        // 右滑,左侧放大
        View rightView = loopViewPagerAdapter.getViews(position - 1);
        if (rightView != null){
          float zoomNext = BASE_SCALE + Math.abs(positionOffset * BASE_INCREMENT);
          rightView.setScaleX(zoomNext);
          rightView.setScaleY(zoomNext);
        }
      }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
      LogUtils.d("LoopViewPager onPageScrollStateChanged --> " + state);
      if (state == 0) {
        int position = getCurrentItem();
        for (int i = 0; i < loopViewPagerAdapter.getViews().length; i++) {
          View itemView = loopViewPagerAdapter.getViews(i);
          if (itemView != null){
            if (i == position){
              loopViewPagerAdapter.getViews(i).setScaleX(BASE_SCALE + BASE_INCREMENT);
              loopViewPagerAdapter.getViews(i).setScaleY(BASE_SCALE + BASE_INCREMENT);
            }else {
              loopViewPagerAdapter.getViews(i).setScaleX(BASE_SCALE);
              loopViewPagerAdapter.getViews(i).setScaleY(BASE_SCALE);
            }
          }
        }
      }
    }
  };

  @SuppressLint("HandlerLeak")
  private class MyHandler extends Handler {

    WeakReference<Context> mWeakReference;

    MyHandler(Context context) {
      mWeakReference = new WeakReference<>(context);
    }

    @Override
    public void handleMessage(Message msg) {
      Context context = mWeakReference.get();
      if (context == null) {
        return;
      }
      if (msg.what == HANDLE_LOOP_MSG) {
        int curItem = getCurrentItem() + 1;
        setCurrentItem(curItem);
      }
      if (isAutoLoop.get()){
        mHandler.sendEmptyMessageDelayed(HANDLE_LOOP_MSG, 3000);
      }
    }
  }

  public int getWidth(Context context) {
    WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    DisplayMetrics outMetrics = new DisplayMetrics();
    if (wm != null) {
      wm.getDefaultDisplay().getMetrics(outMetrics);
    }
    return outMetrics.widthPixels;
  }

  public static class LoopViewPagerAdapter extends PagerAdapter{

    private Context context;
    private ArrayList<Integer> ids = new ArrayList<>();
    private View[] views;
    private int currItem = -1;

    LoopViewPagerAdapter(Context context, ArrayList<Integer> imgIds){
      this.context = context;

      this.ids.add(imgIds.get(imgIds.size()-1));
      this.ids.addAll(imgIds);
      this.ids.add(imgIds.get(0));

      views = new View[ids.size()];
    }

    View getViews(int position) {
      return views[position];
    }

    View[] getViews() {
      return views;
    }

    void initItem(){
      currItem = 1;
    }

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

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

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
      ImageView imageView = new ImageView(context);
      imageView.setImageResource(ids.get(position));

      if (position == currItem){
        imageView.setScaleX(BASE_SCALE + BASE_INCREMENT);
        imageView.setScaleY(BASE_SCALE + BASE_INCREMENT);
        currItem = -1;
      }else {
        imageView.setScaleX(BASE_SCALE);
        imageView.setScaleY(BASE_SCALE);
      }

      container.addView(imageView);
      views[position] = imageView;
      return imageView;
    }
  }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/131247.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • zmq 协议_zmq通信协议

    zmq 协议_zmq通信协议ZMQ通信协议小结前言:最近项目中用到ZMQ,所以研究了一下,总结了一些使用方法!zmq的三种模型: 1、Request_Reply模式: >>一发一收无缓存断开连接数据丢失。 2、Publish-Subscribe模式: >>广播所有client,无缓存,断开连接数据丢失。 3、ParallelPipeline模式 >>由三……

    2025年8月11日
    4
  • 环境贴图_HDR高清环境贴图

    环境贴图_HDR高清环境贴图以前自己看过shader,最近因为被客户逼着搞效果,只能自个儿捣鼓shader。好友把我深深鄙视一番。只好自己单独写篇环境贴图的文章,来小总结一下。环境贴图(EnvironmentMapping)

    2022年8月1日
    4
  • vue跨域解决的几种方案「建议收藏」

    vue跨域解决的几种方案「建议收藏」vue跨域解决的几种方案一、开发环境解决跨域方法平时使用vue开发的时候,大多会使用vue-cli搭建项目,在vue-cli搭建的项目中有一个配置文件vue.config.js,可以在该文件中进行相应的配置解决开发环境的跨域问题。第一步设置公共urlapi/index.jsimportaxiosfrom’axios’importrouterfrom’@/router/index.js’importstorefrom’@/store/index.js’//创建一个axios

    2022年10月1日
    2
  • 标签的含义_新建标签页的网址

    标签的含义_新建标签页的网址功能说明版权信息适用范围首页模板,列表模板,内容模板基本语法[NT:unLoop,NT:SiteID=0,NT:LabelType=CopyRight][/NT:unLoop]必填参数NT:SiteID表示站群ID,0表示总站NT:LabelType标签类型:值为CopyRight,表示版权信息后台设置:控制面板—系统…

    2022年9月30日
    2
  • Python保留小数的方法

    Python保留小数的方法方法一、使用字符串格式化保留n位小数,并做四舍五入处理s=12.3445print(‘%.2f’%s)#12.34s=12.345print(‘%.2f’%s)#12.35方法二、使用round内置函数(会四舍五入)s=12.345a=round(s,2)print(a)#12.35s=12.3445a=round(s,2)print(a)#12.34方法三、使用decimal模块(四舍五入)fromdecimalimportDec

    2022年8月12日
    2
  • IDEA 2022 怎么激活mybatiscodehelperpro-激活码分享

    (IDEA 2022 怎么激活mybatiscodehelperpro)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月31日
    846

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号