ViewPager实现自动轮播效果

来源:互联网 发布:5s是否支持4g网络 编辑:程序博客网 时间:2024/05/01 12:55

花了点时间实现了轮播效果,其中借鉴了一篇博客:轮播效果实现,但是这个里面所有的方法实现都写在一个文件中,真是花费了不少的时间来理清作者思路,这个作者写的内容可以直接拿来使用,我只是将其中的实现模块化实现了,但是只是简单的实现了效果,并没有进行具体的封装,所以仅供参考思路。


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使用。基本上就上述各个点需要注意。

整个项目的截图:

这里写图片描述

源代码:Rotation

0 0
原创粉丝点击