在我们日常生活使用的App中,有很多都带有图片的滚动功能,常见的有网易新闻、今日头条就会使用ViewPager来展示新闻图片。今天我们就来学习一下ViewPager是我们的App更强大美观。
首先看一下今天要实现的效果图


我只做四张图片进行测试,效果包括图片的展示滑动左下角的标题以及右下角的指示点。
现在我们来看一下实现此功能的代码。首先是布局文件activity_main.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="match_parent"
>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/ll_dots"
android:gravity="center_horizontal"
android:layout_alignBottom="@+id/viewpager"
android:layout_alignRight="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</LinearLayout>
</RelativeLayout>
主布局中包括了ViewPager以及LinearLayout两个布局,线性布局的作用是在右下角展示指示点。
展示新闻图片及标题的布局文件vp_item.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="match_parent">
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content" />
</RelativeLayout>
这里我们使用相对布局,layout_alignParentBottom="ture"作用是将TextView即新闻标题放在容器的最低端。
紧接着看一下存放新闻内容的Bean,包括标题及图片不做过多解释。
package com.example.lenovo.viewpager.Bean;
/**
* Created by lenovo on 2017/10/12.
*/
public class News {
private String title;
private int resId;
public News(){
super();
}
public News(String title, int resId) {
this.title = title;
this.resId = resId;
}
@Override
public String toString() {
return "News{" +
"title='" + title + '\'' +
", resId=" + resId +
'}';
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getResId() {
return resId;
}
public void setResId(int resId) {
this.resId = resId;
}
}
接下来才是实现功能的代码,自定义一个适配器它继承PagerAdapter
package com.example.lenovo.viewpager.adapter;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.lenovo.viewpager.Bean.News;
import com.example.lenovo.viewpager.R;
import java.util.ArrayList;
/**
* Created by lenovo on 2017/10/12.
*/
public class MyPagerAdapter extends PagerAdapter {
private Context context;
private ArrayList<News> NewsList;
public MyPagerAdapter(Context context, ArrayList<News> NewsList) {
this.context = context;
this.NewsList = NewsList;
}
/**
* 获取要展示图片的个数
*
*/
@Override
public int getCount() {
return NewsList.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view==object;
}
/**
*初始页面
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view=View.inflate(context, R.layout.vp_item,null);
ImageView imageView=view.findViewById(R.id.imageview);
TextView textView=view.findViewById(R.id.tv_title);
imageView.setImageResource(NewsList.get(position).getResId());
textView.setText(NewsList.get(position).getTitle());
container.addView(view);
return view;
}
/**
*当页面滑动时执行
*/
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
当你实现一个PagerAdapter时,你至少需要重写下面的几个方法:
- instantiateItem(ViewGroup, int)
- destroyItem(ViewGroup, int, Object)
- getCount()
- isViewFromObject(View, Object)
PagerAdapter比很多AdapterView的适配器更加通用。ViewPager使用回调机制来显示一个更新步骤,而不是直接使用视图回收机制。如果需要时,PagerAdapter也可以实现视图回收方法,或者直接使用一种更加巧妙的方法来管理页面,比如直接使用能够管理自身事务的Fragment。
ViewPager并不直接管理页面,而是通过一个key将每个页面联系起来。这个key用来跟踪和唯一标识一个给定的页面,且该key独立于adapter之外。PagerAdapter中的startUpdate(ViewGroup)方法一旦被执行,就说明ViewPager的内容即将开始改变。紧接着,instantiateItem(ViewGroup, int)和/或destroyItem(ViewGroup, int, Object)方法将会被执行,然后finishUpdate(ViewGroup)的执行就意味着这一次刷新的完成。当finishUpdate(ViewGroup)方法执行完时,与instantiateItem(ViewGroup, int)方法返回的key相对应的视图将会被加入到父ViewGroup中,而与传递给destroyItem(ViewGroup, int, Object)方法的key相对应的视图将会被移除。isViewFromObject(View, Object)方法则判断一个视图是否与一个给定的key相对应。
一个简单的PagerAdapter会选择将视图本身作为key,在将视图创建并加入父ViewGroup之后通过instantiateItem(ViewGroup, int)返回。这种情况下,destroyItem(ViewGroup, int, Object) 的实现方法只需要将View从ViewGroup中移除即可,而isViewFromObject(View, Object)的实现方法可以直接写成return view == object;。
PagerAdapter支持数据集的改变。数据集的改变必须放在主线程中,并且在结束时调用notifyDataSetChanged()方法,这与通过BaseAdapter适配的AdapterView类似。一个数据集的改变包含了页面的添加、移除或者位移。ViewPager可以通过在适配器中实现getItemPosition(Object)方法来保持当前页面处于运行状态。
以上内容是官网的解释是不是一头雾水
其实简单来说就是:
instantiateItem(ViewGroup, int)负责初始化指定位置的页面,并且需要返回当前页面本身(其实不一定要View本身,只要是能唯一标识该页面的key都可以,不过初学者一般就先用View本身作为key就可以啦);
destroyItem(ViewGroup, int, Object)负责移除指定位置的页面;
isViewFromObject(View, Object)里直接写“return view == object;”即可(当然,如果你在instantiateItem(ViewGroup, int)里返回的不是View本身,那就不能这么写)。
最后看一下MainActivity
package com.example.lenovo.viewpager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.lenovo.viewpager.Bean.News;
import com.example.lenovo.viewpager.adapter.MyPagerAdapter;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ArrayList<News> NewsList=new ArrayList<News>();
private ViewPager viewPager;
private LinearLayout dots;
private int currentPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewpager);
dots =(LinearLayout) findViewById(R.id.ll_dots);
//初始图片布局
initData();
//初始指示点
initDots();
viewPager.setAdapter(new MyPagerAdapter(MainActivity.this
,NewsList));
viewPager.setCurrentItem(1);//定位第一个新闻
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
*设置偏移量
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
/**
*监听选中的页面
*/
@Override
public void onPageSelected(int position) {
if (position==NewsList.size()-1){
currentPosition=1;
}else if (position==0){
currentPosition=NewsList.size()-2;
}else {
currentPosition=position;
}
changeDots();//随图片变化的指示点
}
/**
*设置滑动状态
*/
@Override
public void onPageScrollStateChanged(int state) {
//SCROLL_STATE_IDLE表示是当前页静止,此状态下将当前页进行替换
if (state== viewPager.SCROLL_STATE_IDLE)
//设置当前页平稳滑动,false闪动,ture慢慢缓缓滑动
viewPager.setCurrentItem(currentPosition,false);
}
});
}
/**
* 将指示点与图片进行配对
*/
public void changeDots(){
int dotPosition=currentPosition-1;
for (int i=0;i<dots.getChildCount();i++) {
ImageView imageView = (ImageView) dots.getChildAt(i);
if (i == dotPosition) {
imageView.setImageResource(R.drawable.button1);
} else {
imageView.setImageResource(R.drawable.button2);
}
}
}
/**
* 初始指示点
*/
private void initDots() {
for (int i=0;i<NewsList.size()-2;i++){
//实际上只有四张图片所以要-2
ImageView imageView=new ImageView(this);
if (i==0){
imageView.setImageResource(R.drawable.button1);
}else{
imageView.setImageResource(R.drawable.button2);
}
dots.addView(imageView);
}
}
/**
* 初始化新闻数据
*/
private void initData() {
//实现无限轮播,从1-4,1左滑动到4,4右滑动到1
NewsList.add(new News("新闻测试四",R.drawable.item4));//索引0
NewsList.add(new News("新闻测试一",R.drawable.itme1));//1
NewsList.add(new News("新闻测试二",R.drawable.item2));//2
NewsList.add(new News("新闻测试三",R.drawable.item3));//3
NewsList.add(new News("新闻测试四",R.drawable.item4));//4
NewsList.add(new News("新闻测试一",R.drawable.itme1));//5
}
}
在代码中实现了无限轮播的功能,在滑动中当处于第一张图片时向左滑动要展示第四张图片,处于第四张图片时向右滑动要展示第一张图片。所以在初始化新闻数据时要添加两个重复的list,实现方法是
@Override
public void onPageSelected(int position) {
//当索引值是5时,跳转为索引值为1的照片
if (position==NewsList.size()-1){
currentPosition=1;
//当索引值为0时使用索引值为4的照片
}else if (position==0){
currentPosition=NewsList.size()-2;
}else {
currentPosition=position;
}
指示点只要与currentPosition配对即可,逻辑基本一致但要注意指示点只有4个而PcurrentPosition有5个所以要-1
/**
* 将指示点与图片进行配对
*/
public void changeDots(){
int dotPosition=currentPosition-1;
for (int i=0;i<dots.getChildCount();i++) {
ImageView imageView = (ImageView) dots.getChildAt(i);
if (i == dotPosition) {
imageView.setImageResource(R.drawable.button1);
} else {
imageView.setImageResource(R.drawable.button2);
}
}
}
这就是实现功能的全部代码,有一些地方可能解释得不太清楚下次争取更大的进步
网友评论