Android中级:轮播图(二):ViewPager实现indicator的滚动

本文详细介绍如何使用Viewpager实现带有图片描述、圆点指示器及进度显示的轮播图无限自动循环滚动效果,并解决了初次加载时的显示问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇博客我们实现了轮播图中viewpager的无限次自动循环滚动的效果,今天我们仅需完善这个demo,实现indicator的滚动效果。indicator包含:图片描述文字 + 圆点 + 或数值(1/5)。

效果图:
这里写图片描述

首先实现 图片描述文字和数值的滚动

先写布局:activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#1A237E"
    tools:context=".MainActivity" >

    <RelativeLayout
        android:id="@+id/relativelayout"
        android:layout_width="match_parent"
        android:layout_height="300dp" >

        <android.support.v4.view.ViewPager
            android:id="@+id/viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerInParent="true" />

        <!-- 图片描述文字 -->
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="100dp"
            android:layout_height="30dp"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="2dp"
            android:ellipsize="end"
            android:gravity="center"
            android:singleLine="true"
            android:text="这是图片描述部分"
            android:textColor="#FFFFFF"
            android:textSize="20sp" />

        <!-- 存放圆点 -->
        <LinearLayout
            android:id="@+id/ll_dots"
            android:layout_width="wrap_content"
            android:layout_height="30dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:gravity="center" >
        </LinearLayout>

        <!-- 第几张图片,共几张图片 -->
        <TextView
            android:id="@+id/tv_ratio"
            android:layout_width="60dp"
            android:layout_height="30dp"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="10dp"
            android:gravity="center"
            android:text="1/5"
            android:textColor="#FFFFFF"
            android:textSize="20sp" />
    </RelativeLayout>


</RelativeLayout>

再实现滚动

在viewpager的滚动监听事件中实现文字和数值的变化。
public void initIndicator() {
    tv_ratio = (TextView) findViewById(R.id.tv_ratio);
    tv_desc = (TextView) findViewById(R.id.tv_desc);    

    viewpager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            tv_desc.setText(des_arrays[position % imageList.size()]);
            tv_ratio.setText(1 + position % imageList.size() + "/" + imageList.size());
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                int positionOffsetPixels) {

        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });
}

接下来,我们实现圆点的变化

也是在viewpager的滚动监听中实现
// 初始化圆点
private void initDots() {
    ll_dots = (LinearLayout) findViewById(R.id.ll_dots);
    ll_dots.removeAllViews();
    tv_dots_list.clear();

    // layout子view的属性
    LayoutParams params = new LayoutParams(10, 10);
    params.setMargins(0, 0, 10, 0);
    for (int i = 0; i < imageList.size(); i++) {
        tv_dot = new TextView(context);
        tv_dot.setBackgroundResource(R.drawable.tv_dot_selector);
        ll_dots.addView(tv_dot, params);
        tv_dots_list.add(tv_dot);
    }
}
public void initIndicator() {
    viewpager.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            ....
            for (int i = 0; i < tv_dots_list.size(); i++) {
                if (i == position % imageList.size()) {
                    tv_dots_list.get(i).setSelected(true);
                } else {
                    tv_dots_list.get(i).setSelected(false);
                }
            }
        }
        ....
    });
}

其中:tv_dot_selector.xml是:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/dot_focus" android:state_selected="true"></item>
    <item android:drawable="@drawable/dot_normal"></item>

</selector>

Bug

Bug1:

这样,我们基本实现了轮播图的效果,但是有一个bug没有解决,就是第一次打开这个app时,图片是不是第一张图片,圆点也不是第一个,怎么可以做到从第一张开始滚动呢?

错误原因:

viewpager.setCurrentItem(1001);// 当前页是1001页,也即是1页:因为1001%5=1,而不是0.

解决方法:

viewpager.setCurrentItem(imageList.size() * 1000);// 当前页是5000页,也即是0页:因为5000%5=0.

Bug2:

图片是从第一张开始,但是西面的文字描述+圆点+数值不对。
文字描述是刚开始是xml默认的文字,数值也是xml默认的文字,圆点是灰色的,只有从第二张图片开始,文字描述+圆点+数值才正常,这是问什么呢?

错误原因:
我们把viewpager的setCurrentItem(..)放在了setOnPageChangeListener(…)前面,应该监听在前,然后是设置当前页。
2种解决方法
方法一:监听在前,然后是设置当前页。

// 初始化指示器
initIndicator();//监听pager的变化
viewpager.setCurrentItem(imageList.size() * 1000);// 当前页是5000页,也即是0页:因为5000%5=0.

方法二:设置文字描述+圆点+数值的默认值是第1页

viewpager.setCurrentItem(imageList.size() * 1000);// 当前页是5000页,也即是0页:因为5000%5=0.
// 初始化指示器
initIndicator();//监听pager的变化

// 默认从第1个开始。
tv_desc.setText(des_arrays[0]);
tv_ratio.setText("1/5");
tv_dots_list.get(0).setSelected(true);

完整的代码是:

package com.cqc.viewpagerdemo;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TextView;

public class MainActivity extends Activity {

    protected static final String tag = "MainActivity";
    private ViewPager viewpager;
    private List<ImageView> imageList = new ArrayList<ImageView>();
    private List<TextView> tv_dots_list = new ArrayList<TextView>();
    private Context context;
    int msgWhat = 0;
    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);// 收到消息,指向下一个页面
            handler.sendEmptyMessageDelayed(msgWhat, 2000);// 2S后在发送一条消息,由于在handleMessage()方法中,造成死循环。
            Log.d(tag, "handleMessage");
        };
    };
    private TextView tv_ratio;
    private LinearLayout ll_dots;
    private TextView tv_dot;
    private TextView tv_desc;
    private String[] des_arrays;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = this;
        initViewPagerData();// 初始化viewpager中存放的数据
        initDesData();// 图片描述数据

        viewpager = (ViewPager) findViewById(R.id.viewpager);
        viewpager.setAdapter(new MyAdapter());

        viewpager.setCurrentItem(imageList.size() * 1000);// 当前页是5000页,也即是0页:因为5000%5=0.
        // 初始化指示器
        initIndicator();//监听pager的变化

        // 默认从第1个开始。
        tv_desc.setText(des_arrays[0]);
        tv_ratio.setText("1/5");
        tv_dots_list.get(0).setSelected(true);
    }

    private void initDesData() {
        des_arrays = getResources().getStringArray(R.array.des_array);
    }

    // 初始化圆点
    private void initDots() {
        ll_dots = (LinearLayout) findViewById(R.id.ll_dots);
        ll_dots.removeAllViews();
        tv_dots_list.clear();

        // LinearLayout的宽高
        LayoutParams params = new LayoutParams(10, 10);
        // layout子view的间距
        params.setMargins(0, 0, 10, 0);
        for (int i = 0; i < imageList.size(); i++) {
            tv_dot = new TextView(context);
            tv_dot.setBackgroundResource(R.drawable.tv_dot_selector);
            ll_dots.addView(tv_dot, params);
            tv_dots_list.add(tv_dot);
        }
    }

    public void initIndicator() {
        tv_ratio = (TextView) findViewById(R.id.tv_ratio);
        tv_desc = (TextView) findViewById(R.id.tv_desc);
        initDots();// 初始化圆点

        viewpager.setOnPageChangeListener(new OnPageChangeListener() {

            @Override
            public void onPageSelected(int position) {
                tv_desc.setText(des_arrays[position % imageList.size()]);
                tv_ratio.setText(1 + position % imageList.size() + "/"
                        + imageList.size());
                for (int i = 0; i < tv_dots_list.size(); i++) {
                    if (i == position % imageList.size()) {
                        tv_dots_list.get(i).setSelected(true);
                    } else {
                        tv_dots_list.get(i).setSelected(false);
                    }
                }
            }

            @Override
            public void onPageScrolled(int position, float positionOffset,
                    int positionOffsetPixels) {

            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    private void initViewPagerData() {
        imageList.clear();
        ImageView iva = new ImageView(context);
        iva.setBackgroundResource(R.drawable.a);

        ImageView ivb = new ImageView(context);
        ivb.setBackgroundResource(R.drawable.b);

        ImageView ivc = new ImageView(context);
        ivc.setBackgroundResource(R.drawable.c);

        ImageView ivd = new ImageView(context);
        ivd.setBackgroundResource(R.drawable.d);

        ImageView ive = new ImageView(context);
        ive.setBackgroundResource(R.drawable.e);

        imageList.add(iva);
        imageList.add(ivb);
        imageList.add(ivc);
        imageList.add(ivd);
        imageList.add(ive);
    }

    public class MyAdapter extends PagerAdapter {
        // 表示viewpager共存放了多少个页面
        @Override
        public int getCount() {
            return Integer.MAX_VALUE;// 我们设置viewpager中有Integer.MAX_VALUE个页面
        }

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

        /**
         * position % imageList.size() 而不是position,是为了防止角标越界异常
         * 因为我们设置了viewpager子页面的数量有Integer.MAX_VALUE,而imageList的数量只是5。
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(imageList.get(position % imageList.size()));
            return imageList.get(position % imageList.size());
        }

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

    /**
     * activity可见可交互的时候就开始发送消息,开启循环
     */
    @Override
    protected void onResume() {
        super.onResume();
        handler.sendEmptyMessageDelayed(msgWhat, 2000);
    }

    /**
     * 当MainActivity不可见的时候让handler停止发送消息 防止内存泄露
     */
    @Override
    protected void onStop() {
        super.onStop();
        handler.removeMessages(msgWhat);
    }

}

轮播图(含indicator)的无限自动循环滚动

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值