画廊效果的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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 手把手教你用Hexo+Github 搭建属于自己的博客「建议收藏」

    手把手教你用Hexo+Github 搭建属于自己的博客「建议收藏」欢迎关注我的微信公众号,扫一扫下方二维码或搜索微信号stormjun,即可关注。目前专注于Android开发,主要分享Android开发相关知识和一些相关的优秀文章,包括个人总结,职场经验等。闲聊在大三的时候,一直就想搭建属于自己的一个博客,但由于各种原因,最终都不了了之,恰好最近比较有空,于是就自己参照网上的教程,搭建了属于自己的博客。至于为什么要搭建自己的博客了?

    2022年7月27日
    5
  • WinExec、ShellExecute和CreateProcess

    WinExec、ShellExecute和CreateProcess有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。CreateProcess因为使用复杂,比较少用。    WinExec主要运行EXE文件。  ⑴ 函数原型: UINT Win Exec(LPCSTR lpCmdLine, UINT uCmdShow);   ⑵ 参数:   lpCmdLine:指向一个空结束的字符串,串中包含将要执行的应用程…

    2022年7月11日
    19
  • Linux入门命令_零基础自学吉他的步骤

    Linux入门命令_零基础自学吉他的步骤Linux入门基础命令教程linux用户识别查看文件与目录命令三级目录linux用户识别这里我就不详细介绍什么是linux,相比你来看文章的都知道什么是linux。linux用户分为两种,分别是管理员用户和普通用户,当我们登录linux的时候会看到如下图第一部分是用户名@demon是主机名/当前所在路径root是管理员用户demon是普通用户可以看到他们的区别在于最后的字符,#是管理员用户的意思,$是普通用户的意思。查看文件与目录命令1.pwd查看当前所在的目录如图

    2022年10月10日
    2
  • 代理设计模式详解(java版本)

    代理设计模式详解(java版本)

    2021年8月2日
    59
  • linux rm 命令详解,Linux rm命令使用指南「建议收藏」

    linux rm 命令详解,Linux rm命令使用指南「建议收藏」Linux系统的众多命令中,rm命令主要用于删除文件,下面小编就来详解介绍下Linux系统的rm命令,希望对初学者有一定的帮助。名称:rm使用权限:所有使用者使用方式:rm[options]name.。。说明:删除档案及目录。参数:?-i删除前逐一询问确认。-f即使原档案属性设为唯读,亦直接删除,无需逐一确认。-r将目录及以下之档案亦逐一删除。范例:删除所有C语言程式档;删除前逐一询问确…

    2025年6月29日
    4
  • webpack的devtool[通俗易懂]

    webpack的devtool[通俗易懂]这里以环境分类为分析方向1.对开发环境eval-每个模块都使用eval()执行,并且都有//@sourceURL。此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从loader中获取sourcemap),所以不能正确的显示行数。eval-source-map-每个模块使用eval()执行,并且sourcem…

    2022年10月5日
    2

发表回复

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

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