上一篇博客我们实现了轮播图中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);
}
}