Android开发,使用ViewPager2实现自动轮播图

在Android项目程序设计中,首页轮播图是个很常见的功能,在之前的文章中,教了大家如何使用第三方库来快速实现轮播图(教程地址在文章末尾给出),今天教大家手把手来撸一个轮播图

1. build.gradle添加依赖:

图片显示,采用Glide来加载网络图片

implementation 'com.github.bumptech.glide:glide:4.12.0'

2. AndroidManifest.xml中添加网络访问权限

 <uses-permission android:name="android.permission.INTERNET" />

3. 编写 布局文件

activity_banner.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:id="@+id/indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="10dp"
        android:orientation="horizontal" />

</RelativeLayout>

4. 编写Banner适配器

BannerAdapter.java

public class BannerAdapter extends RecyclerView.Adapter<BannerAdapter.BannerViewHolder> {
    
    
    private List<String> imageUrls;
    private Context context;

    public BannerAdapter(Context context, List<String> imageUrls) {
    
    
        this.context = context;
        this.imageUrls = imageUrls;
    }

    @NonNull
    @Override
    public BannerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    
    
        ImageView imageView = new ImageView(context);
        imageView.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        return new BannerViewHolder(imageView);
    }

    @Override
    public void onBindViewHolder(@NonNull BannerViewHolder holder, int position) {
    
    
        // 使用实际位置加载图片
        int realPosition = position % imageUrls.size();
        // 这里使用Glide加载图片,需要添加Glide依赖
        Glide.with(context)
                .load(imageUrls.get(realPosition))
                .into(holder.imageView);
        
        holder.imageView.setOnClickListener(v -> {
    
    
            // 处理图片点击事件
            if (onItemClickListener != null) {
    
    
                onItemClickListener.onItemClick(realPosition);
            }
        });
    }

    @Override
    public int getItemCount() {
    
    
        // 返回一个很大的数,实现无限循环
        return Integer.MAX_VALUE;
    }

    static class BannerViewHolder extends RecyclerView.ViewHolder {
    
    
        ImageView imageView;

        public BannerViewHolder(@NonNull View itemView) {
    
    
            super(itemView);
            imageView = (ImageView) itemView;
        }
    }

    // 点击事件接口
    public interface OnItemClickListener {
    
    
        void onItemClick(int position);
    }

    private OnItemClickListener onItemClickListener;

    public void setOnItemClickListener(OnItemClickListener listener) {
    
    
        this.onItemClickListener = listener;
    }
}

这里注意:在方法onBindViewHolder中,Glide加载图片,需要添加Glide依赖

5. 自定义Banner视图

BannerView.java

public class BannerView extends RelativeLayout {
    
    
    private ViewPager2 viewPager;
    private LinearLayout indicator;
    private List<ImageView> indicatorDots;
    private Handler handler;
    private static final int SCROLL_TIME = 3000; // 自动滚动间隔
    private boolean isAutoScroll = true;

    public BannerView(Context context) {
    
    
        super(context);
        init(context);
    }

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

    private void init(Context context) {
    
    
        // 加载布局
        LayoutInflater.from(context).inflate(R.layout.activity_banner, this, true);
        viewPager = findViewById(R.id.viewPager);
        indicator = findViewById(R.id.indicator);
        indicatorDots = new ArrayList<>();
        handler = new Handler(Looper.getMainLooper());
    }

    public void setImages(List<String> imageUrls) {
    
    
        // 设置适配器
        BannerAdapter adapter = new BannerAdapter(getContext(), imageUrls);
        viewPager.setAdapter(adapter);
        
        // 设置初始位置到中间
        viewPager.setCurrentItem(Integer.MAX_VALUE / 2, false);
        
        // 创建指示器
        createIndicators(imageUrls.size());
        
        // 设置页面切换监听
        viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
    
    
            @Override
            public void onPageSelected(int position) {
    
    
                updateIndicator(position % imageUrls.size());
            }
        });

        // 开始自动滚动
        startAutoScroll();
    }

    private void createIndicators(int count) {
    
    
        indicator.removeAllViews();
        indicatorDots.clear();

        for (int i = 0; i < count; i++) {
    
    
            ImageView dot = new ImageView(getContext());
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    dpToPx(8), dpToPx(8));
            params.setMargins(dpToPx(4), 0, dpToPx(4), 0);
            dot.setLayoutParams(params);
            dot.setImageResource(R.drawable.dot_normal);
            indicator.addView(dot);
            indicatorDots.add(dot);
        }

        // 设置第一个点为选中状态
        if (!indicatorDots.isEmpty()) {
    
    
            indicatorDots.get(0).setImageResource(R.drawable.dot_selected);
        }
    }

    private void updateIndicator(int position) {
    
    
        for (int i = 0; i < indicatorDots.size(); i++) {
    
    
            indicatorDots.get(i).setImageResource(
                    i == position ? R.drawable.dot_selected : R.drawable.dot_normal);
        }
    }

    private void startAutoScroll() {
    
    
        handler.postDelayed(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                if (isAutoScroll && viewPager != null) {
    
    
                    viewPager.setCurrentItem(viewPager.getCurrentItem() + 1);
                    handler.postDelayed(this, SCROLL_TIME);
                }
            }
        }, SCROLL_TIME);
    }

    public void stopAutoScroll() {
    
    
        isAutoScroll = false;
        handler.removeCallbacksAndMessages(null);
    }

    private int dpToPx(int dp) {
    
    
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dp, 
                getResources().getDisplayMetrics());
    }

    @Override
    protected void onDetachedFromWindow() {
    
    
        super.onDetachedFromWindow();
        stopAutoScroll();
    }
}

6. 定义圆点指示器的drawable资源

  1. dot_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#80FFFFFF" />
    <size
        android:width="8dp"
        android:height="8dp" />
</shape>
  1. dot_selected.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#FFFFFF" />
    <size
        android:width="8dp"
        android:height="8dp" />
</shape>

这里注意:dot_normal.xml和dot_selected.xml创建在res下的drawable中,而不是res下的layout

7. 在需要使用轮播图中的Activity中使用

  1. MainActivity.java
public class MainActivity extends AppCompatActivity {
    
    
    private BannerView bannerView;

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

        bannerView = findViewById(R.id.banner_view);
        
        // 准备图片URL列表
        List<String> imageUrls = new ArrayList<>();
        imageUrls.add("https://img0.baidu.com/it/u=2673431480,3550145287&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=211");
        imageUrls.add("https://img1.baidu.com/it/u=1588549273,1647024151&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=312");
        imageUrls.add("https://img2.baidu.com/it/u=3920432635,2105461872&fm=253&fmt=auto&app=138&f=JPEG?w=1600&h=500");
        imageUrls.add("https://img1.baidu.com/it/u=921161528,741350508&fm=253&fmt=auto&app=138&f=PNG?w=658&h=380");
        imageUrls.add("https://img2.baidu.com/it/u=611817443,624986336&fm=253&fmt=auto&app=138&f=JPEG?w=1280&h=407");
        // 设置图片
        bannerView.setImages(imageUrls);
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        if (bannerView != null) {
    
    
            bannerView.stopAutoScroll();
        }
    }
}

这里注意:一定要在Activity生命周期的onDestroy()中调用 bannerView.stopAutoScroll()方法

  1. activity_main.xml
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="200dp">

    <com.app.skill.sharing.views.BannerView
        android:id="@+id/banner_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</androidx.appcompat.widget.LinearLayoutCompat>

com.app.skill.sharing.views.BannerView :这里自定义控件的使用为:包名+类名。具体根据自己自定义控件存放的位置而定,在编辑器中输入Ban…,跟使用系统自带控件一样,编辑器会智能提示

扫描二维码关注公众号,回复: 17610679 查看本文章

8. 运行效果图

在这里插入图片描述

9. 视频教程

  1. Androidstudio轮播图Banner实现 :https://www.bilibili.com/video/BV18B4y1R7gy/?vd_source=984bb03f768809c7d33f20179343d8c8