Android簡(jiǎn)單實(shí)現(xiàn)無(wú)限滾動(dòng)自動(dòng)滾動(dòng)的ViewPager
經(jīng)常我們會(huì)在應(yīng)用中看到一個(gè)可以自動(dòng)滾動(dòng),并且無(wú)限滾動(dòng)的一個(gè)ViewPager,百度谷歌上面也有很多關(guān)于這方面的教程,但是感覺(jué)都略顯麻煩,而且封裝的都不是很徹底。所以試著封裝一個(gè)比較好用的ViewPager
效果如下:

簡(jiǎn)單的說(shuō)一下實(shí)現(xiàn)思路,要實(shí)現(xiàn)無(wú)限滾動(dòng)的話(huà)就要在PagerAdapter上面做一些手腳,在PagerAdapter的getCount的函數(shù)的返回值設(shè)置成Integer.MXA_VALUE就可以實(shí)現(xiàn)向右無(wú)限滾動(dòng),但是要實(shí)現(xiàn)向左無(wú)限滾動(dòng)呢?就是一開(kāi)始的時(shí)候setCurrentItem的時(shí)候設(shè)置一個(gè)非常大的值(大到你向左滾動(dòng)了一萬(wàn)年還是有東西)
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
mPager.setCurrentItem(10000 * mDatas.size());//一開(kāi)始設(shè)置成這樣的話(huà)就可以向左無(wú)限滾動(dòng)了
然后另外一個(gè)就是底部的游標(biāo)了:

底部的游標(biāo)是用一個(gè)自定義視圖:無(wú)非就是畫(huà)一個(gè)背景,然后在畫(huà)一個(gè)高亮的游標(biāo)
/**
* 指示游標(biāo)
*/
private class TipView extends View {
private int mPadding;
private int mCount;
private int mCurPos;
private Paint mNorPaint;//未被選中的顏色
private Paint mSelPaint;//被選中的顏色 白色
private int mHeight;
public TipView(Context context, int count) {
super(context);
mNorPaint = new Paint();
mNorPaint.setAntiAlias(true);
int selHeight = ShowUtils.dip2px(2);
int norHeight = ShowUtils.dip2px(1);
mHeight = ShowUtils.dip2px(2);
mNorPaint.setStrokeWidth(norHeight);
mNorPaint.setColor(Color.argb(80, 255, 255, 255));
mSelPaint = new Paint();
mSelPaint.setAntiAlias(true);
mSelPaint.setStrokeWidth(selHeight);
mSelPaint.setColor(Color.WHITE);
mCount = count;
mPadding = ShowUtils.dip2px(0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int ow = (getWidth()-2 * mPadding)/ mCount;
int y = getHeight() / 2;
canvas.drawLine(mPadding, y, mCurPos * ow + mPadding, y, mNorPaint);
canvas.drawLine(mCurPos * ow + mPadding, y, (mCurPos + 1) * ow + mPadding, y, mSelPaint);
canvas.drawLine((mCurPos + 1) * ow + mPadding, y, getWidth() - mPadding, y, mNorPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup.LayoutParams vp = getLayoutParams();
vp.width = ViewGroup.LayoutParams.MATCH_PARENT;
vp.height = mHeight;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setCurPostion(int pos) {
mCurPos = pos;
invalidate();
}
public void setCount(int count) {
mCount = count;
}
}
R.layout.layout_recommend_item的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@null"
android:scaleType="fitXY"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:background="@drawable/recommend"
android:gravity="center">
<TextView
android:id="@+id/tv_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:textSize="@dimen/text_normal"
android:maxLines="1"
android:ellipsize="end"
android:shadowColor="#ff333333"
android:shadowDx="2"
android:shadowDy="2"
android:paddingRight="8dp"
android:paddingLeft="8dp"
android:shadowRadius="1" />
</LinearLayout>
</RelativeLayout>
還有一個(gè)是實(shí)現(xiàn)自動(dòng)滾動(dòng),自動(dòng)滾動(dòng)的話(huà)就是監(jiān)聽(tīng)OnPagerChangeListener里面的函數(shù),在ViewPager狀態(tài)改變的時(shí)候利用Handler發(fā)送一個(gè)切換界面的消息:
@Override
public void onPageScrollStateChanged(int i) {
curState = i;
if(i == ViewPager.SCROLL_STATE_DRAGGING){ //viewpager正在被拖動(dòng)的時(shí)候
stopAnimation();
}else { //沒(méi)有可執(zhí)行消息時(shí)候添加消息 實(shí)現(xiàn)自動(dòng)滾動(dòng)
if(!(sHandler.hasMessages(START_SCROLL)&&sHandler.hasMessages(SCROLL_NEXT))){
startAnimation();
}
}
}
@Override
public void onPageSelected(final int i) { //頁(yè)面跳轉(zhuǎn)后得到調(diào)用
sHandler.removeMessages(SCROLL_NEXT);
sHandler.removeMessages(START_SCROLL);
if(curState == ViewPager.SCROLL_STATE_DRAGGING){
return;
}
Message msg = sHandler.obtainMessage(SCROLL_NEXT);
msg.arg1 = i + 1;
msg.obj = mPager;
sHandler.sendMessageDelayed(msg, SHOW_TIME);
mTipView.setCurPostion(i % mDatas.size());
}
整體的代碼:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.papau.show.R;
import com.papau.show.entity.HeadViewEntity;
import com.papau.show.utils.ShowUtils;
import java.util.ArrayList;
import java.util.List;
public class RecommendView extends RelativeLayout implements IRecommend {
private static final int START_SCROLL = 1;
private static final int SCROLL_NEXT = 2;
private static final int SHOW_TIME = 5000;
private List<HeadViewEntity> mDatas = new ArrayList<>();
private ViewPager mPager;
private Context mContext;
private int mWidth, mHeight;
private ImageLoader mLoader;
private DisplayImageOptions mOptions;
private int mTitleHeight;
private TipView mTipView;
private static Handler sHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
int w = msg.what;
ViewPager pager = (ViewPager) msg.obj;
switch (w) {
case START_SCROLL:
pager.setCurrentItem(msg.arg1, true);
break;
case SCROLL_NEXT:
pager.setCurrentItem(msg.arg1, true);
break;
}
}
};
public RecommendView(Context context) {
super(context);
}
public RecommendView(Context context, int w, int h) {
super(context);
mContext = context;
mWidth = w;
mHeight = h;
initView();
// mPager.setAdapter(new RecommendAdapter());
mPager.setOnPageChangeListener(new MOnPagerChangeListener());
mLoader = ImageLoaderManager.getImageLoader(mContext);
mOptions = ImageLoaderManager.getCacheOnDiskOptions(mContext);
init();
// DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
mTitleHeight = ShowUtils.dip2px(48);//設(shè)置游標(biāo)高度
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup.LayoutParams vp = getLayoutParams();
if (vp != null) { //設(shè)置視圖的寬高
vp.width = mWidth;
vp.height = mHeight;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void initView() {
mPager = new ViewPager(mContext);
RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
addView(mPager, rp);
}
/**
* 初始化指示游標(biāo)
*/
private void initTipView() {
if (mTipView == null) {
RelativeLayout.LayoutParams rp = new RelativeLayout.LayoutParams(10, 10);
rp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);//顯示在父控件的底部
rp.bottomMargin = mTitleHeight;//游標(biāo)的高度
mTipView = new TipView(mContext, mDatas.size());
addView(mTipView, rp);
} else {
mTipView.setCount(mDatas.size());
}
}
@Override
public void upDate() {
getData();
}
@Override
public void init() {
getData();
}
@Override
public void startAnimation() {
if (mDatas.size() == 0) {
return;
}
Message msg = sHandler.obtainMessage(START_SCROLL);
msg.obj = mPager;
msg.arg1 = (mPager.getCurrentItem() + 1);
sHandler.sendMessageDelayed(msg, SHOW_TIME);
}
@Override
public void stopAnimation() {
sHandler.removeMessages(START_SCROLL);
sHandler.removeMessages(SCROLL_NEXT);
}
/**
* 獲取viewpager要顯示的數(shù)據(jù)
*/
private void getData() {
String[] imageData = new String[]{"http://f.hiphotos.baidu.com/image/h%3D360/sign=e105b9f1d61b0ef473e89e58edc651a1/b151f8198618367a9f738e022a738bd4b21ce573.jpg",
"http://c.hiphotos.baidu.com/image/h%3D360/sign=b8cea9e92b738bd4db21b437918b876c/f7246b600c3387448982f948540fd9f9d72aa0bb.jpg",
"http://a.hiphotos.baidu.com/image/h%3D360/sign=3da95d01e7dde711f8d245f097eecef4/71cf3bc79f3df8dc39cb6295cf11728b461028c4.jpg",
"http://d.hiphotos.baidu.com/image/h%3D360/sign=410c3c96a60f4bfb93d09852334f788f/10dfa9ec8a136327a1de913a938fa0ec08fac78c.jpg",
"http://e.hiphotos.baidu.com/image/h%3D360/sign=f6600b1613dfa9ece22e501152d1f754/342ac65c10385343ff41ee2b9113b07eca808829.jpg"};
for (int i = 0; i < 5; i++) {
HeadViewEntity info = new HeadViewEntity();
info.setImageUrl(imageData[i]);
info.setTitle("我不做大哥好多年"+i);
info.setUrl("www.baidu.com");
mDatas.add(info);
}
sHandler.postDelayed(new Runnable() {
@Override
public void run() {
stopAnimation();
initTipView();
mPager.setAdapter(new RecommendAdapter());
mPager.setCurrentItem(10000 * mDatas.size());//一開(kāi)始設(shè)置成這樣的話(huà)就可以向左無(wú)限滾動(dòng)了
}
},2000);
}
/**
* viewpager子項(xiàng)內(nèi)容
*/
private class RecommendAdapter extends PagerAdapter {
/**
* 填充子項(xiàng)視圖的內(nèi)容
* @param container 父控件 viewpager
* @param position 子項(xiàng)的位置
* @return 返回子項(xiàng)視圖
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
int curPos = position % mDatas.size();
View view = View.inflate(mContext, R.layout.layout_recommend_item, null);
ViewGroup.LayoutParams vp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
ImageView iv = (ImageView) view.findViewById(R.id.iv_pic);
TextView tv = (TextView) view.findViewById(R.id.tv_desc);
tv.setText(mDatas.get(curPos).getTitle());
mLoader.displayImage(mDatas.get(curPos).getImageUrl(), iv, mOptions);
container.addView(view, vp);
view.setTag(curPos);
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public int getCount() {
return Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(View view, Object o) {
return view == o;
}
}
private class MOnPagerChangeListener implements ViewPager.OnPageChangeListener {
private int curState;
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageScrollStateChanged(int i) {
curState = i;
if(i == ViewPager.SCROLL_STATE_DRAGGING){ //viewpager正在被拖動(dòng)的時(shí)候
stopAnimation();
}else { //沒(méi)有可執(zhí)行消息時(shí)候添加消息 實(shí)現(xiàn)自動(dòng)滾動(dòng)
if(!(sHandler.hasMessages(START_SCROLL)&&sHandler.hasMessages(SCROLL_NEXT))){
startAnimation();
}
}
}
@Override
public void onPageSelected(final int i) { //頁(yè)面跳轉(zhuǎn)后得到調(diào)用
sHandler.removeMessages(SCROLL_NEXT);
sHandler.removeMessages(START_SCROLL);
if(curState == ViewPager.SCROLL_STATE_DRAGGING){
return;
}
Message msg = sHandler.obtainMessage(SCROLL_NEXT);
msg.arg1 = i + 1;
msg.obj = mPager;
sHandler.sendMessageDelayed(msg, SHOW_TIME);
mTipView.setCurPostion(i % mDatas.size());
}
}
/**
* 指示游標(biāo)
*/
private class TipView extends View {
private int mPadding;
private int mCount;
private int mCurPos;
private Paint mNorPaint;//未被選中的顏色
private Paint mSelPaint;//被選中的顏色 白色
private int mHeight;
public TipView(Context context, int count) {
super(context);
mNorPaint = new Paint();
mNorPaint.setAntiAlias(true);
int selHeight = ShowUtils.dip2px(2);
int norHeight = ShowUtils.dip2px(1);
mHeight = ShowUtils.dip2px(2);
mNorPaint.setStrokeWidth(norHeight);
mNorPaint.setColor(Color.argb(80, 255, 255, 255));
mSelPaint = new Paint();
mSelPaint.setAntiAlias(true);
mSelPaint.setStrokeWidth(selHeight);
mSelPaint.setColor(Color.WHITE);
mCount = count;
mPadding = ShowUtils.dip2px(0);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int ow = (getWidth()-2 * mPadding)/ mCount;
int y = getHeight() / 2;
canvas.drawLine(mPadding, y, mCurPos * ow + mPadding, y, mNorPaint);
canvas.drawLine(mCurPos * ow + mPadding, y, (mCurPos + 1) * ow + mPadding, y, mSelPaint);
canvas.drawLine((mCurPos + 1) * ow + mPadding, y, getWidth() - mPadding, y, mNorPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup.LayoutParams vp = getLayoutParams();
vp.width = ViewGroup.LayoutParams.MATCH_PARENT;
vp.height = mHeight;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setCurPostion(int pos) {
mCurPos = pos;
invalidate();
}
public void setCount(int count) {
mCount = count;
}
}
}
然后提供了一個(gè)接口調(diào)用:
/**
* RecommendView接口
*/
public interface IRecommend {
void upDate();
void init();
void startAnimation();
void stopAnimation();
}
圖片的加載用到了ImageLoad庫(kù):
import android.content.Context;
import android.graphics.Bitmap;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.papau.show.constant.Constants;
import java.io.File;
public class ImageLoaderManager {
/**
* 不帶硬盤(pán)緩存的options
*
* @param context
* @return
*/
public static synchronized DisplayImageOptions getCacheOnMemoryOptions(Context context) {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(false)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.bitmapConfig(Bitmap.Config.ARGB_8888)
// .showImageOnLoading(
// context.getResources().getDrawable(
// R.drawable.loading_wait))
// .showImageOnFail(
// context.getResources().getDrawable(
// R.drawable.loading_wait))
.build();
return options;
}
public static synchronized DisplayImageOptions getCircleOptions(Context context) {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(false)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
.bitmapConfig(Bitmap.Config.ARGB_8888)
// .showImageOnLoading(
// context.getResources().getDrawable(
// R.drawable.ic_user_head_hint))
// .showImageOnFail(
// context.getResources().getDrawable(
// R.drawable.ic_user_head_hint))
.build();
return options;
}
/**
* 獲取在硬盤(pán)中緩存options
*
* @param context
* @return options
*/
public static synchronized DisplayImageOptions getCacheOnDiskOptions(
Context context) {
DisplayImageOptions options = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisk(true)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.ARGB_8888)
// .showImageOnLoading(
// context.getResources().getDrawable(
// R.drawable.loading_wait))
// .showImageOnFail(
// context.getResources().getDrawable(
// R.drawable.loading_wait))
.build();
return options;
}
/**
* 獲取imageLoader 單例
*
* @param context
* @return
*/
public static synchronized ImageLoader getImageLoader(Context context) {
ImageLoader imageLoader = ImageLoader.getInstance();
File cacheDir = new File(Constants.sPicCacheLocalPath);
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
context).diskCache(new UnlimitedDiskCache(cacheDir))
.threadPoolSize(3)
.diskCacheExtraOptions(480, 320, null)
.build();
imageLoader.init(config);
return imageLoader;
}
}
使用方法
DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
RecommendView rv = new RecommendView(getActivity(),dm.widthPixels ,(dm.widthPixels)/2);
headViewPager.addView(rv);
以上所述是小編給大家介紹的Android簡(jiǎn)單實(shí)現(xiàn)無(wú)限滾動(dòng)自動(dòng)滾動(dòng)的ViewPager,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- android 實(shí)現(xiàn)ScrollView自動(dòng)滾動(dòng)的實(shí)例代碼
- android ListView自動(dòng)滾動(dòng)方法
- Android使用Recyclerview實(shí)現(xiàn)圖片水平自動(dòng)循環(huán)滾動(dòng)效果
- android scrollview 自動(dòng)滾動(dòng)到頂部或者底部的實(shí)例
- Android 使用ViewPager自動(dòng)滾動(dòng)循環(huán)輪播效果
- Android ViewPager無(wú)限循環(huán)滑動(dòng)并可自動(dòng)滾動(dòng)完整實(shí)例
- Android ListView滾動(dòng)到底后自動(dòng)加載數(shù)據(jù)
- Android使用自定義屬性實(shí)現(xiàn)圖片自動(dòng)播放滾動(dòng)的功能
- Android編程實(shí)現(xiàn)TextView垂直自動(dòng)滾動(dòng)功能【附demo源碼下載】
- Android自定義TextBanner實(shí)現(xiàn)自動(dòng)滾動(dòng)
相關(guān)文章
Android實(shí)現(xiàn)仿美團(tuán)、順豐快遞數(shù)據(jù)加載效果
本片文章教給大家用Android實(shí)現(xiàn)美團(tuán)和順豐快遞APP的數(shù)據(jù)加載的動(dòng)畫(huà)效果,有興趣的朋友跟著學(xué)習(xí)嘗試下吧。2017-12-12
Android Studio 3.0中mipmap-anydpi-v26是什么東東
在Android Studio 3.0中一旦我們創(chuàng)建了一個(gè)項(xiàng)目,一個(gè)名為mipmap-anydpi-v26自動(dòng)創(chuàng)建的文件夾在res文件夾下。它究竟能干什么?為什么我們需要這個(gè)?我們?cè)陂_(kāi)發(fā)時(shí)該如何利用它,下面通過(guò)本文給大家介紹下2017-12-12
Android Activity啟動(dòng)模式之singleTop實(shí)例詳解
這篇文章主要介紹了Android Activity啟動(dòng)模式之singleTop,結(jié)合實(shí)例形式較為詳細(xì)的分析了singleTop模式的功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-01-01
Android編程Widget創(chuàng)建與使用方法簡(jiǎn)明教程
這篇文章主要介紹了Android編程Widget創(chuàng)建與使用方法,結(jié)合實(shí)例形式分析了Widget的功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-10-10
Flutter Reusable Lottie Animations技巧
這篇文章主要為大家介紹了Flutter Reusable Lottie Animations技巧,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android編程實(shí)現(xiàn)拍照功能的2種方法分析
這篇文章主要介紹了Android編程實(shí)現(xiàn)拍照功能的2種方法,結(jié)合具體實(shí)例形式對(duì)比分析了Android通過(guò)調(diào)用系統(tǒng)攝像頭及程序調(diào)用照相機(jī)功能兩種實(shí)現(xiàn)技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07
android自定義進(jìn)度條漸變色View的實(shí)例代碼
這篇文章主要介紹了android自定義進(jìn)度條漸變色View的實(shí)例代碼,有需要的朋友可以參考一下2014-01-01
Android開(kāi)發(fā)中常見(jiàn)問(wèn)題
這篇文章主要為大家詳細(xì)介紹了Android開(kāi)發(fā)中常見(jiàn)問(wèn)題,主要涉及了七個(gè)問(wèn)題,希望能幫助到大家,感興趣的小伙伴們可以參考一下2016-06-06

