ViewPager实现自动轮播效果
花了点时间实现了轮播效果,其中借鉴了一篇博客:轮播效果实现,但是这个里面所有的方法实现都写在一个文件中,真是花费了不少的时间来理清作者思路,这个作者写的内容可以直接拿来使用,我只是将其中的实现模块化实现了,但是只是简单的实现了效果,并没有进行具体的封装,所以仅供参考思路。1.抽象SingleFragmentActivity类。参考《Android编程权威指南》中作者的意见,抽象出了一套Fragme
花了点时间实现了轮播效果,其中借鉴了一篇博客:轮播效果实现,但是这个里面所有的方法实现都写在一个文件中,真是花费了不少的时间来理清作者思路,这个作者写的内容可以直接拿来使用,我只是将其中的实现模块化实现了,但是只是简单的实现了效果,并没有进行具体的封装,所以仅供参考思路。
1.抽象SingleFragmentActivity类。
参考《Android编程权威指南》中作者的意见,抽象出了一套Fragment的代码用来使用,基本可以实现大多数的情况,代码如下:
SingleFragmentActivity.java
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
}
其中需要的布局代码很简单:
activity_fragment.xml
"><FrameLayout
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"/>```
使用的时候也比较简单了,需要实现的活动直接继承SingleFragmentActivity即可,然后实现其createFragment方法即可。这样的话,就可以将Fragment托管到Activity中去使用,其中fragment就可以通过FragmentManager来进行管理了。
2.创建RotationActivity继承SingleFragmentActivity。
正如上面所介绍的,我们需要创建一个轮播的Activity,其继承与SingleFragmentActivity类,实现其中的createFragment方法,所以我们就需要一个Fragment。
RotationActivity.java
public class RotationActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return RotationFragment.newInstance();
}
}
RotationFragment.java
public static Fragment newInstance() {
return new RotationFragment();
}
```
由于我们需要一个Fragment,所以我们创建了一个RotationFragment类(这里只给出了创建该实例的方法,其他方法会逐渐给出),然后用一个静态方法,可以通过该静态方法来创建该实例。
以上的内容都只是基础的,下面才开始要进行主要内容的实现了。
3.使用Asset读取本地图片。
这里我并没有使用网络来加载图片,直接使用了本地的图片,然后通过加载直接使用。
首先创建一个图片的模型类,其中存放了图片的一些信息:
ImageInfo.java
public class ImageInfo {
private String mUrl;
private String mTitle;
private Bitmap mBitmap;
public Bitmap getBitmap() {
return mBitmap;
}
public void setBitmap(Bitmap bitmap) {
mBitmap = bitmap;
}
public String getUrl() {
return mUrl;
}
public void setUrl(String url) {
mUrl = url;
}
public String getTitle() {
return mTitle;
}
public void setTitle(String title) {
mTitle = title;
}
}
然后我们需要管理本地的图片,创建一个ImagesManager类:
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.BitmapFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Created by leafage on 2017/3/25.
*/
public class ImagesManager {//用来管理图片的信息
private AssetManager mAssets;//用来管理Assets资源
private List<ImageInfo> mImageInfos = new ArrayList<>();
public ImagesManager(Context context) {
mAssets = context.getAssets();
loadImages();
}
private void loadImages() {
String[] imageNames;//用来存储图片的名字
try {
imageNames = mAssets.list("rotation_images");//得到images目录下的文件名
for (String name : imageNames) {
ImageInfo imageInfo = new ImageInfo();
String fileName = name.split("\\.")[0];//去除文件的后缀
imageInfo.setTitle(fileName);
InputStream inputStream = mAssets.open("rotation_images" + "/" + name);
imageInfo.setBitmap(BitmapFactory.decodeStream(inputStream));
mImageInfos.add(imageInfo);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
public List<ImageInfo> getImageInfos() {
return this.mImageInfos;
}
}
这个类使用了asset技术读取本地的图片,然后初始化每个图片信息,比如得到图片的名字、将图片转换成Bitmap类型,然后添加到一个List中,最后可以通过调用getImageInfos方法得到所有的图片模型信息。
4.将图片生成ViewPager所需要的Vew。
由于ViewPager中我们需要一组视图,所以我么可以将上面得到的图片转换成一组View来供ViewPager使用。我将其单独写到了一个类中:
InitImagesViewList.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by leafage on 2017/3/26.
*/
public class InitImagesViewList {
private Context mContext;
private ImagesManager mImagesManager;
public InitImagesViewList(Context context) {
mContext = context;
mImagesManager = new ImagesManager(context);
}
public List<View> getImageViewList() {//根据传来的图片信息,初始化生成View
List<View> mViews = new ArrayList<>();
List<ImageInfo> imageInfos = mImagesManager.getImageInfos();
for (int i = 0; i < imageInfos.size() + 2; i++) {
View view = LayoutInflater.from(mContext).inflate(R.layout.image_title, null);
ImageView imageView = (ImageView) view.findViewById(R.id.rotation_image);
TextView textView = (TextView) view.findViewById(R.id.rotation_title);
if (i == 0) {//第一个放最后一张视图
imageView.setImageBitmap(imageInfos.get(imageInfos.size() - 1).getBitmap());
textView.setText(imageInfos.get(imageInfos.size() - 1).getTitle());
} else {
if (i == imageInfos.size() + 1) {//最后一张放第一张
imageView.setImageBitmap(imageInfos.get(0).getBitmap());
textView.setText(imageInfos.get(0).getTitle());
} else {//其他情况就正常放置
imageView.setImageBitmap(imageInfos.get(i - 1).getBitmap());
textView.setText(imageInfos.get(i - 1).getTitle());
}
}
mViews.add(view);
}
return mViews;
}
}
我这里一共有三张图片,但是为了制造从最后一张也可以滑动到第一张图片的效果,就将最后一张图片复制一张放到最前面,拿出第一张图片放到最后面。如果有1、2、3,三张图,构造完之后就是3、1、2、3、1,有五张图片。我们滑动的时候展现在用户面前的就是123,但是当最后一张3继续向右滑动的时候,就会出现1的图片,这时候我们调用ViewPager的setCurrentItem方法,再隐式的跳转到1就行了。
然后我们写一个类用来监听ViewPager事件,然后重写其中的onPageScrollStateChanged方法:
@Override
public void onPageScrollStateChanged(int state) {
//Log.i("leafage", "onPageScrollStateChanged:" + state);
switch (state) {
case ViewPager.SCROLL_STATE_IDLE://当停下来的时候
if (mViewPager.getCurrentItem() == 4) {
mViewPager.setCurrentItem(1, false);
//Log.i("leafage", "最后一个转换成第一个");
}
if (mViewPager.getCurrentItem() == 0) {
mViewPager.setCurrentItem(3, false);
//Log.i("leafage", "第一个转换成最后一个");
}
break;
case ViewPager.SCROLL_STATE_DRAGGING://滑动中
mIsAutoPlay = false;
break;
case ViewPager.SCROLL_STATE_SETTLING://手指已经不再继续滑动了
mIsAutoPlay = true;
break;
default:
break;
}
}
5.设置ViewPager的Adapter。
在Adapter中就需要实现其抽象方法,返回相对应的内容即可。
ViewPagerAdapter.java
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
/**
* Created by leafage on 2017/3/25.
*/
public class ViewPagerAdapter extends PagerAdapter {
private List<View> mViews;
/**
* 用来存放View视图
* @param mViews
*/
public ViewPagerAdapter(List<View> Views) {
this.mViews = Views;
}
@Override
public int getCount() {//得到view的个数
return mViews.size();
}
//判断是否page view与 instantiateItem(ViewGroup, int)返回的object的key 是否相同,以提供给其他的函数使用
//官方建议这样写
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//创建给定位置的界面
@Override
public Object instantiateItem(ViewGroup container, final int position) {
View view = mViews.get(position);//得到当前的视图,并添加点击事件
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d("leafage", "Onclick : " + position);
}
});
container.addView(view);
return view;
}
//删除当前位置的视图
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViews.get(position));
}
}
6.实现自动轮播。
上述的步骤完成之后,现在应该可以手动进行滑动了,离我们自动轮播相差不远了。
使用Handler中的postDelayed方法就能够实现。在run方法中进行自动调用即可,其中需要判断一下此时图片有没有被拖动,被拖动的话就不要自动播放了。
@Override
public void run() {
if (mRotationChangeListener.isAutoPlay()) {//自动播放,说明现在没有手指滑动
int currentItem = mViewPager.getCurrentItem();//得到当前的位置
currentItem = (currentItem % mViewCounts) + 1;
mViewPager.setCurrentItem(currentItem);
mHandler.postDelayed(this, mDelay);
} else {//现在不是自动播放,等待五秒,看看能不能播放了
mHandler.postDelayed(this, 5000);
}
}
7.设置小圆点指示器。
完成上述的步骤就已经能够自动无限制轮播了,但是还缺少一点就是下面的指示器来展示我们正处于第几个视图中。
原点指示器的话设置两个变大变小的动画,然后在ViewPagwer中的onPageSelected中进行转换调用动画:
public void onPageSelected(int position) {
//Log.i("leafage", "onPageSelected :" + position);
for (int i = 0; i < mDots; i++) {//遍历一下全部的小圆点,把当前的小圆点设置变大动画,其他的都变小
if (i == position - 1) {//得到当前的小圆点索引值
IndicatorDot.mLinearLayout.getChildAt(i).setBackgroundResource(R.drawable.checked);
mAnimatorDot.DotLargen(IndicatorDot.mLinearLayout.getChildAt(i));//变大
IndicatorDot.sState.put(i, true);
} else {//如果不是当前的话,如果处于选中状态则改变成为选中状态
if (IndicatorDot.sState.get(i)) {
IndicatorDot.mLinearLayout.getChildAt(i).setBackgroundResource(R.drawable.unchecked);
mAnimatorDot.DotMinify(IndicatorDot.mLinearLayout.getChildAt(i));//变小
IndicatorDot.sState.put(i, false);
}
}
}
}
小圆点的话,共分为两个步骤一个就是动画的设置,一个就是基本属性的设置:
基本属性设置:
public void InitIndicationDot() {
for (int i = 0; i < mDots; i++) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mDotWidth, mDotHeight);
layoutParams.leftMargin = 15;
layoutParams.rightMargin = 15;
layoutParams.bottomMargin = 15;
layoutParams.topMargin = 15;
View view = new View(mContext);
view.setBackgroundResource(R.drawable.unchecked);
mLinearLayout.addView(view, layoutParams);
sState.put(i, false);
}
sState.put(0, true);
}
动画的设置在源码中给出,再次不在羸述。
8.整合所有的功能。
至此,各个模块之间都已经写好了,然后在RotationFragment.java中进行整合调用。
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import android.os.Handler;
import android.widget.LinearLayout;
/**
* Created by leafage on 2017/3/25.
*/
public class RotationFragment extends Fragment {
private ViewPager mViewPager;
private List<View> mViews;//用来存放视图
private InitImagesViewList mInitImagesViewList;//用来初始化信息得到视图
private ViewPagerAdapter mViewPagerAdapter;//用来给ViewPager设置的Adapter
private RotationChangeListener mRotationChangeListener;//设置滑动时监听
private boolean isAutoPlay = true;//用来记录现在是不是自动播放,默认是True
private Handler mHandler;
private AutoPlay mAutoPlay;
private LinearLayout mLinearLayout;//用来管理小圆点指示器的线性布局.
private IndicatorDot mIndicatorDot;//用来设置小圆点指示器的类。
public static Fragment newInstance() {
return new RotationFragment();
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInitImagesViewList = new InitImagesViewList(getContext());
mViews = mInitImagesViewList.getImageViewList();
mViewPagerAdapter = new ViewPagerAdapter(mViews);
mHandler = new Handler();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rotation, container, false);
mViewPager = (ViewPager) view.findViewById(R.id.viewPager);
mLinearLayout = (LinearLayout) view.findViewById(R.id.indicator_dot);
mIndicatorDot = new IndicatorDot(getContext(),mLinearLayout, mViews.size() - 2);//减去多余的两张视图
mIndicatorDot.setDots(35,35);
mIndicatorDot.InitIndicationDot();
mRotationChangeListener = new RotationChangeListener(getContext(),mViewPager,isAutoPlay,mIndicatorDot.getDots());//设置滚动监听
mViewPager.setAdapter(mViewPagerAdapter);//设置适配器
mViewPager.addOnPageChangeListener(mRotationChangeListener);//设置滑动监听
mViewPager.setCurrentItem(1);//设置开始的下标,也就是第二张图,因为第一张是就是最后一张
mAutoPlay = new AutoPlay(mViewPager,3000,mRotationChangeListener,mHandler,mViews.size());
mHandler.postDelayed(mAutoPlay, 3000);
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(mAutoPlay);
}
}
所有的内容大致就是这样了,没有进行详细的介绍,大致思路已经完全给出。如果不使用本地图片的话,可以采用Glide或者Picasso框架进行动态加载也是可以的。个人认为整体来说没有特别困难的地方,主要是整体的流程和各个模块之间的配合使用。需要了解ViewPager的setCurrentItem使用和OnPageChangeListener中的各个回调方法的回调时间,简单动画的使用以及Handler中的postDelayed使用。基本上就上述各个点需要注意。
整个项目的截图:
更多推荐
所有评论(0)