Android的左右滑动在实际编程中经常能用到,自android 3.0之后的sdk中提供了android-support-v4包用以实现版本兼容,让老版本系统下的应用通过导入jar包实现扩展
使用步骤:
1.在布局文件中创建viewPager标签,如果一个页面仅仅显示viewpager不显示其他的话根标签可以随便设置,如果还要显示其他视图(例如在下面显示几个点),一般设置为帧布局.(标签为v4包下的倒数第三个包下的最后一个类)
2.在MainActivity中初始化布局,获得viewpager布局。并创建viewpager中要显示的页面布局(一般创建List<View>集合,然后创建view将其添加到集合中去)
3.将数据源添加到List<View>集合中,为集合的每个元素添加数据
4.创建适配器,新建一个类继承PagerAdapter(PagerAdapter直接继承Object类),重写其下的4个方法(必须重写),在该方法中要获得数据源(view页面布局)
public int getCount()//获得数据的总数(即滑动页面的个数)
public Object instantiateItem(ViewGroup container, int position)//第一:将当前视图添加到container(容器)中,第二:返回当前View(参数一为adapter作用的对象,即Adapter放在哪个控件上(也可以说是父节点,参数二为指定view的索引))
public boolean isViewFromObject(View arg0, Object arg1)//判断是否由对象生成初始化界面一般直接将返回值改为:return arg0==arg1;
public void destroyItem(ViewGroup container, int position, Object object)//从当前container中删除指定位置(position)的View;
5.创建适配器对象,并让viewpager关联适配器
实例:viewpager实现轮播图效果
imageview设置的图片我是直接copy到drawable文件夹下的,用的时候可以根据自己不同的需求去写
xml布局代码
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.luuuzi.demo001.MainActivity">
<RelativeLayout
android:layout_width="368dp"
android:layout_height="160dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="7dp">
<android.support.v4.view.ViewPager
android:id="@+id/vp"
android:layout_width="368dp"
android:layout_height="160dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="0dp"></android.support.v4.view.ViewPager>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:background="#666666">
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="天王盖地虎"
android:textColor="#ffffff"
android:textSize="17sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
效果图
mainActivity代码
package com.example.luuuzi.demo001;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TextView tv_desc;
private ViewPager vp;
private int[] imageResIds;
private ImageView imageView;
private ArrayList<ImageView> imageViews;
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
//配置适配器
initAdapter();
}
private void initView() {
vp = (ViewPager) findViewById(R.id.vp);
tv_desc = (TextView) findViewById(R.id.tv_desc);
}
private void initData() {
//数据源添加数据
imageViews = new ArrayList<>();
imageResIds = new int[]{R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e};
for (int i=0;i<imageResIds.length;i++){
imageView =new ImageView(MainActivity.this);
imageView.setImageResource(imageResIds[i]);
imageViews.add(imageView);
}
}
private void initAdapter() {
adapter = new MyAdapter();
//设置2的话就说明左右各加载2个,即最多完全加载5个(左右各2个中间1个)
//vp.setOffscreenPageLimit(2);
vp.setAdapter(adapter);
}
class MyAdapter extends PagerAdapter{
@Override
public int getCount() {
return imageViews.size();
}
/**
* 指定复用的判断逻辑
* 当我们滑到新的条目后又返回来,当前的view是否被复用,
* @param view
* @param object
* @return 判断规则
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;//固定写法
}
/**
* 返回要显示的条目内容
* 该方法主要做2件事:1.把要显示的view对象添加到containner中
* 2.把view对象返回的框架(适配器),必须重写,不然抛异常
* @param container 容器:当前的viewpager
* @param position 当前显示条目的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
//1.1.把要显示的view对象添加到containner中
container.addView(imageViews.get(position));
return imageViews.get(position);//必须重写,否则抛异常
}
/**
*
* @param container
* @param position
* @param object 要销毁的对象
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
以上实现的是5张图片可以滑动
给轮播图下面加5个小圆点实现图片选中后对应的小圆点高亮显示,代码如下
package com.example.luuuzi.demo001;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TextView tv_desc;
private ViewPager vp;
private int[] imageResIds;
private ImageView imageView;
private ArrayList<ImageView> imageViews;
private MyAdapter adapter;
private View pointView;
private LinearLayout ll;
//标记,第二种小白点设置方法的标记
private int lastEnabled=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
//配置适配器
initAdapter();
}
private void initView() {
vp = (ViewPager) findViewById(R.id.vp);
tv_desc = (TextView) findViewById(R.id.tv_desc);
ll = (LinearLayout) findViewById(R.id.ll);
}
private void initData() {
//数据源添加数据
imageViews = new ArrayList<>();
imageResIds = new int[]{R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e};
for (int i=0;i<imageResIds.length;i++){
imageView =new ImageView(MainActivity.this);
imageView.setImageResource(imageResIds[i]);
imageViews.add(imageView);
//小圆点的添加,指示器
pointView = new View(MainActivity.this);
//设置背景
pointView.setBackgroundResource(R.drawable.select_bg_point);
//设置都是未选中状态
pointView.setEnabled(false);
//给小白点设置布局参数,设置小白点的长宽 5,5
LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(10,10);
if(i!=0)
params.leftMargin=10;
//将小白点添加到布局上去
ll.addView(pointView,params);
}
}
private void initAdapter() {
adapter = new MyAdapter();
//设置第一个小白点为选中状态,通过父布局拿到第1个子控件
ll.getChildAt(0).setEnabled(true);
//设置预加载个数,默认为左右个一个,即最多完全加载3个
//vp.setOffscreenPageLimit(2);//设置2的话就说明左右各加载2个,即最多完全加载5个(左右各2个中间1个)
vp.setAdapter(adapter);
vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 滑动时调用
* @param position
* @param positionOffset
* @param positionOffsetPixels
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
/**
* 选中后监听
* @param position
*/
@Override
public void onPageSelected(int position) {
// for(int i=0;i<ll.getChildCount();i++){
// if(position==i){
// //选中的
// ll.getChildAt(position).setEnabled(true);
// }else {
// ll.getChildAt(i).setEnabled(false);
// }
// }
/**
* 或者
*/
//把之前的禁用,把最新的启用,这样也可以实现
ll.getChildAt(lastEnabled).setEnabled(false);
ll.getChildAt(position).setEnabled(true);
lastEnabled=position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
class MyAdapter extends PagerAdapter{
@Override
public int getCount() {
return imageViews.size();
}
/**
* 指定复用的判断逻辑
* 当我们滑到新的条目后又返回来,当前的view是否被复用,
* @param view
* @param object
* @return 判断规则
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;//固定写法
}
/**
* 返回要显示的条目内容
* 该方法主要做2件事:1.把要显示的view对象添加到containner中
* 2.把view对象返回的框架(适配器),必须重写,不然抛异常
* @param container 容器:当前的viewpager
* @param position 当前显示条目的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
//1.1.把要显示的view对象添加到containner中
container.addView(imageViews.get(position));
return imageViews.get(position);//必须重写,否则抛异常
}
/**
*
* @param container
* @param position
* @param object 要销毁的对象
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}
shape布局
shape_bg_enable.xml
<?xml version="1.0" encoding="utf-8"?>
<!--选中的原点-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!--半径-->
<corners android:radius="10dp"/>
<!--背景-->
<solid
android:color="#ffffff"/>
</shape>
shape_bg_point.xml
<?xml version="1.0" encoding="utf-8"?>
<!--选中的原点-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<!--半径-->
<corners android:radius="10dp"/>
<!--背景-->
<solid
android:color="#cccccc"/>
</shape>
select_bg_point.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="true" android:drawable="@drawable/shap_bg_enable"/>
<item android:state_enabled="false" android:drawable="@drawable/shap_bg_point"/>
</selector>
实现左右可以无限滑动
//原理:1,先实现往右无限滑动,当我们的数据设置为特别大的时候就可以保证我们滑不完即无限滑动
@Override
public int getCount() {
//实现无限循环,把值设成最大
return Integer.MAX_VALUE;
}
//以上就吧数据设置为int的最大值,但是有个问题就是在getView中填数据的时候因为Position会大于没我的数据,所以会出现越界
//解决:
@Override public Object instantiateItem(ViewGroup container, int position) { //1.1.把要显示的view对象添加到containner中 /** * 实现无限循环 * position:当显示的条目位置>4时 * 5-》0 * 6-》1 * 7-》2 */ newPosition = position%5; container.addView(imageViews.get(newPosition)); return imageViews.get(newPosition);//必须重写,否则抛异常 }
小圆点的设置
//其他地方的position也要设置成newPosition,防止越界
以上就实现了右边滑动,显示要实现左边滑动,原理;如果我们把Adapter的初始位置设置为中间位置,这样就实现了左右都可以无限滑
private void initAdapter() {
adapter = new MyAdapter();
//设置第一个小白点为选中状态,通过父布局拿到第1个子控件
ll.getChildAt(0).setEnabled(true);
tv_desc.setText(contentDescs[0]);
//
//设置预加载个数,默认为左右个一个,即最多完全加载3个
//vp.setOffscreenPageLimit(2);//设置2的话就说明左右各加载2个,即最多完全加载5个(左右各2个中间1个)
vp.setAdapter(adapter);
//设置默认显示中间某个页面 而不是0,实现左右滑都可以无限滑
int pos=Integer.MAX_VALUE/2-(Integer.MAX_VALUE/2%imageViews.size());
vp.setCurrentItem(pos);
vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 滑动时调用
* @param position
* @param positionOffset
* @param positionOffsetPixels
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
/**
* 选中后监听
* @param position
*/
@Override
public void onPageSelected(int position) {
// for(int i=0;i<ll.getChildCount();i++){
// if(position==i){
// //选中的
// ll.getChildAt(position).setEnabled(true);
// }else {
// ll.getChildAt(i).setEnabled(false);
// }
// }
/**
* 或者
*/
//把之前的禁用,把最新的启用,这样也可以实现
ll.getChildAt(lastEnabled).setEnabled(false);
ll.getChildAt(newPosition).setEnabled(true);
lastEnabled=newPosition;
tv_desc.setText(contentDescs[newPosition]);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
自动滑动的实现
//实现自动滑动
MainActivity完整代码:
package com.example.luuuzi.demo001;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TextView tv_desc;
private ViewPager vp;
private int[] imageResIds;
private ImageView imageView;
private ArrayList<ImageView> imageViews;
private MyAdapter adapter;
private View pointView;
private LinearLayout ll;
//添加标记,防止越滑越快
private boolean isRuning=false;
//内容
private String[] contentDescs=new String[]{"巩俐不低俗,我就不能低俗",
"朴树又回来了",
"揭秘北京电影如何升级",
"乐视网tv大派送",
"热血屌丝反射"};
//标记,第二种小白点设置方法的标记
private int lastEnabled=0;
private int newPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
//配置适配器
initAdapter();
/**
* 定时任务
*/
//开启一个轮询
new Thread(){
@Override
public void run() {
isRuning=true;
while (isRuning){
//每2s执行一次
try {
Thread.sleep(2*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//往下跳一格
runOnUiThread(new Runnable() {
@Override
public void run() {
vp.setCurrentItem(vp.getCurrentItem()+1);
}
});
}
}
}.start();
}
private void initView() {
vp = (ViewPager) findViewById(R.id.vp);
tv_desc = (TextView) findViewById(R.id.tv_desc);
ll = (LinearLayout) findViewById(R.id.ll);
}
private void initData() {
//数据源添加数据
imageViews = new ArrayList<>();
imageResIds = new int[]{R.drawable.a,R.drawable.b,R.drawable.c,R.drawable.d,R.drawable.e};
for (int i=0;i<imageResIds.length;i++){
imageView =new ImageView(MainActivity.this);
imageView.setImageResource(imageResIds[i]);
imageViews.add(imageView);
//小圆点的添加,指示器
pointView = new View(MainActivity.this);
//设置背景
pointView.setBackgroundResource(R.drawable.select_bg_point);
//设置都是未选中状态
pointView.setEnabled(false);
//给小白点设置布局参数,设置小白点的长宽 5,5
LinearLayout.LayoutParams params=new LinearLayout.LayoutParams(10,10);
if(i!=0)
params.leftMargin=10;
//将小白点添加到布局上去
ll.addView(pointView,params);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
isRuning=false;
}
private void initAdapter() {
adapter = new MyAdapter();
//设置第一个小白点为选中状态,通过父布局拿到第1个子控件
ll.getChildAt(0).setEnabled(true);
tv_desc.setText(contentDescs[0]);
//
//设置预加载个数,默认为左右个一个,即最多完全加载3个
//vp.setOffscreenPageLimit(2);//设置2的话就说明左右各加载2个,即最多完全加载5个(左右各2个中间1个)
vp.setAdapter(adapter);
//设置默认显示中间某个页面 而不是0,实现左右滑都可以无限滑
int pos=Integer.MAX_VALUE/2-(Integer.MAX_VALUE/2%imageViews.size());
vp.setCurrentItem(pos);
vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 滑动时调用
* @param position
* @param positionOffset
* @param positionOffsetPixels
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
/**
* 选中后监听
* @param position
*/
@Override
public void onPageSelected(int position) {
// for(int i=0;i<ll.getChildCount();i++){
// if(position==i){
// //选中的
// ll.getChildAt(position).setEnabled(true);
// }else {
// ll.getChildAt(i).setEnabled(false);
// }
// }
/**
* 或者
*/
//把之前的禁用,把最新的启用,这样也可以实现
ll.getChildAt(lastEnabled).setEnabled(false);
ll.getChildAt(newPosition).setEnabled(true);
lastEnabled=newPosition;
tv_desc.setText(contentDescs[newPosition]);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
class MyAdapter extends PagerAdapter{
@Override
public int getCount() {
//实现无限循环,把值设成最大
return Integer.MAX_VALUE;
}
/**
* 指定复用的判断逻辑
* 当我们滑到新的条目后又返回来,当前的view是否被复用,
* @param view
* @param object
* @return 判断规则
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;//固定写法
}
/**
* 返回要显示的条目内容
* 该方法主要做2件事:1.把要显示的view对象添加到containner中
* 2.把view对象返回的框架(适配器),必须重写,不然抛异常
* @param container 容器:当前的viewpager
* @param position 当前显示条目的位置
* @return
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
//1.1.把要显示的view对象添加到containner中
/**
* 实现无限循环
* position:当显示的条目位置>4时
* 5-》0
* 6-》1
* 7-》2
*/
newPosition = position%5;
container.addView(imageViews.get(newPosition));
return imageViews.get(newPosition);//必须重写,否则抛异常
}
/**
*
* @param container
* @param position
* @param object 要销毁的对象
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
}