網上80%的思路關於Android輪播圖無限循環都是不正確的,不是真正意義上的無限循環,
其思路大多是將ViewPager的getCount方法返回值設置為Integer.MAX_VALUE,
然后呢將ViewPager的當前展示頁設置為第1000頁或者是10000頁,這樣用戶一般情況下是滑不到邊界的
例如有5張圖片的輪播圖,item的編號為(0,1,2,3,4)當前頁的頁號如果是5, 這時候就將編號設置為0,即
actPosition %= datas.size();這個公式就是這么來的
這種思路實現的無限輪播雖然可以實現需求 但是卻不是真正意義的無限輪播,結合了iOS 、HTML5的無限輪播圖實現思路,總結如下:
例如:有五張輪播圖 item的編號為(0,1,2,3,4) 要想實現 無限循環 我們在這五張的頭部和尾部各加一張即(5+2)張,item編號為(0,1,2,3,4,5,6)其中編號為0,6的兩張不做展示只是為了做循環輪播的鋪墊,
1、當我們從編號為5 右滑的時候到了編號6 這時候就將當前頁面設置為1
2、當我們從編號為1左滑的時候到了編號0 這時候就將當前頁面設置為5
第一種情況:
第二種情況:
這么做之后就可以實現無限輪播 怎么保證從編號6跳轉編號1的時候不出現頁面停頓 突然跳到下一頁的現象呢?
public Object instantiateItem (ViewGroup container, int position)
在指定的位置創建頁面;適配器負責添加view到這個容器中,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
public void destroyItem (ViewGroup container, int position, Object object)
刪除指定位置的頁面;適配器負責從view容器中刪除view,然而它只保證在finishUpdate(ViewGroup)返回時才完成。
所以說 重點就在於finishUpdate(ViewGroup)這個方法 其實無論是創建view添加到容器中 還是 銷毀view 都是在此方法結束之后執行的
換句話說 就是 我在這個方法里讓頁面完成從 編號5跳轉到編號1 或者從編號1跳轉到編號5,此方法完成時 視圖還未完成創建或者 銷毀 這樣也就不會出現 頁面停頓 突然跳到下一頁的現象
@Override public void finishUpdate(ViewGroup container) { int position = mBanner.getCurrentItem(); if (position == 0) { position = datas.size(); viewPager.setCurrentItem(position,false); } else if (position == (datas.size()+2) - 1) { position = 1; viewPager.setCurrentItem(position,false); } }
如此 完美解決 無限輪播
一般情況下 輪播圖要求自動輪播 沒關系 我們可以利用Handler去開啟線程 讓其每隔一定時間去輪播
這里的重點是 如果我們定義每隔3秒輪播一張,當我們用手滑動了之后這時候要重新計時,防止用戶剛滑動完 程序立馬又滑動一次,
handler.removeCallbacksAndMessages(null);
此方法意思是移除所有的定消息 handler.sendEmptyMessageDelayed(0,3000);
此方法是三秒之后發送一個 message.what=0的消息
完整的代碼
我定義了一個View名字叫TopView 實現每隔3秒輪播,並且下方有小圓點(當前顯示的編號小圓點會變成白色,其他小圓點顯示為灰色)的輪播圖
基本思路是 在FrameLayout里邊底層是一個Viewpager 上層是一個LinearLayout 里邊有對應張數的小圓點 小圓點是根據數據的個數動態生成的
類里邊還定義了一個 點擊監聽接口 ,點擊對應的圖片可以回調給調用者
public class TopView extends FrameLayout implements ViewPager.OnPageChangeListener { private ViewPager vPager; private List<ImageView> imgViews; private List<String> datas;// 數據源 private LinearLayout navLayout; private LinearLayout.LayoutParams layoutParams;//線性布局中子控件使用的布局參數,作用設置子控件大小,外邊距 private Context mContext; private DownLoadImage imageLoader; private int currentPosition=0; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); currentPosition = (++currentPosition) % imgViews.size(); vPager.setCurrentItem(currentPosition,false); //處理完之前的消息之后再次發送一個3秒之后的消息 如此 可實現每隔三秒輪播 if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } }; public TopView(Context context) { this(context,null); } public TopView(Context context, AttributeSet attrs) { this(context,attrs,0); } public TopView(Context context,AttributeSet attrs,int defStyle) { super(context,attrs,defStyle); mContext=context; // 第二個參數this: 布局資源中根標簽內聲明的布局參數參考的父控件對象 // 第三個參數true: 代表是將第一個參數中聲明的子控件歸屬到第二個參數對象中,false不歸屬 LayoutInflater.from(context).inflate(R.layout.topview, this, true); initView(); } private void initView() { // 查找相關的UI控件 vPager = (ViewPager) findViewById(R.id.viewPager); navLayout = (LinearLayout) findViewById(R.id.navLayout); } public void setData(List<String> datas) { this.datas = datas; createViews(); } private void createViews() { // 根據數據源創建ViewPager中顯示的UI imgViews = new ArrayList<ImageView>();//加入數據源 layoutParams =new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT); // layoutParams.leftMargin=20; layoutParams.rightMargin=10;//px layoutParams.width=20; layoutParams.height=20; ImageView imgView = null; ImageView navImg = null; for (int i=0;i<datas.size();i++) { imgView = new ImageView(getContext()); imgView.setScaleType(ImageView.ScaleType.FIT_XY); imgView.setTag(datas.get(i)); imgViews.add(imgView); navImg = new ImageView(getContext()); navImg.setScaleType(ImageView.ScaleType.CENTER_CROP); if(i==0) navImg.setImageResource(R.drawable.page_now); else navImg.setImageResource(R.drawable.page); //設置導航圖片的標簽: 當前導航圖片的位置 navImg.setTag(i); navImg.setLayoutParams(layoutParams); navLayout.addView(navImg); } vPager.setAdapter(new ImageAdapter()); vPager.addOnPageChangeListener(this); loadImgs(); //開啟handler的線程 3秒之后發出此消息 if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } private void loadImgs() { // 加載網絡圖片加載后放入imageView for (int i=0;i<datas.size();i++) { String data=datas.get(i); for (ImageView imageView : imgViews) { if(imageView.getTag().equals(data)){ getImageView(imageView,data,i); } } } } class ImageAdapter extends PagerAdapter { @Override public int getCount() { return datas.size()+2; } @Override public boolean isViewFromObject(View arg0, Object arg1) { // TODO Auto-generated method stub return arg0 == arg1; } @Override public Object instantiateItem(ViewGroup container, int actPosition) { //對Viewpager頁號求模去除View列表中要顯示的項 actPosition %= datas.size(); ImageView view = imgViews.get(actPosition); //如果View已經在之前添加到了一個父組件,則必須先remove,否則會拋出IllegalStateException。 ViewParent viewParent = view.getParent(); if (viewParent!=null){ ViewGroup parent = (ViewGroup)viewParent; parent.removeView(view); } container.addView(view); return view; } @Override public void destroyItem(ViewGroup container, int actPosition, Object object) { //注意不在此方法進行removeView } @Override public void finishUpdate(ViewGroup container) { super.finishUpdate(container); int position = vPager.getCurrentItem(); if (position == 0) { position = datas.size(); currentPosition=position; if(handler!=null){ handler.removeCallbacksAndMessages(null); handler.sendEmptyMessageDelayed(0,3000); } vPager.setCurrentItem(position,false); } else if (position == (datas.size()+2) - 1) { position = 1; currentPosition=position; if(handler!=null){ handler.removeCallbacksAndMessages(null); handler.sendEmptyMessageDelayed(0,3000); } vPager.setCurrentItem(position,false); } } } @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override public void onPageSelected(int position) { position=position % datas.size(); if(handler!=null){ handler.removeCallbacksAndMessages(null); } currentPosition=position; ImageView navImg = null; //遍歷 導航布局中所有的子控件,判斷子控件的位置是否為選擇位置,若是,則改變圖片的內容 for(int i=0;i<navLayout.getChildCount();i++){ navImg = (ImageView) navLayout.getChildAt(i );//獲取布局中指定位置的子控件 if(i==position) navImg.setImageResource(R.drawable.page_now); else navImg.setImageResource(R.drawable.page); } if(handler!=null){ handler.sendEmptyMessageDelayed(0,3000); } } public interface TopViewClickListener{ public void onTopViewClick(int position); } public TopViewClickListener mTopViewClickListener; public void setTopViewClickListener(TopViewClickListener topViewClickListener){ mTopViewClickListener=topViewClickListener; } private ImageView getImageView(ImageView imageView,String url, final int position) { imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (mTopViewClickListener != null) { mTopViewClickListener.onTopViewClick(position); } } }); if (imageLoader == null) { imageLoader = new DownLoadImage(mContext, R.drawable.bannerdefault, R.drawable.bannerdefault, null); } imageLoader.displayImage(url, imageView, null); return imageView; } }
TopView類中用到的布局文件
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:id="@+id/navLayout" android:layout_height="30dp" android:layout_width="match_parent" android:layout_gravity="bottom" android:gravity="center" android:orientation="horizontal" /> </FrameLayout>
如何調用:
在activity_main.xml中
<com.myview.TopView android:id="@+id/topview" android:layout_width="match_parent" android:layout_height="@dimen/size_600px"/>
在MainActivity 中的偽代碼:
private TopView topView; public class ActivityMain extends Activity implements TopView.TopViewClickListener{
public void onCreate(。。。。。){ //urls是圖片的地址 topView.setData(urls); topView= (TopView) findViewById(R.id.topview); //設置點擊圖片事件的監聽器 topView.setTopViewClickListener(this); } @Override public void onTopViewClick(int position) { if (datas!= null && datas.size() > 0) { //用position去加載對應的數據即可 } } }
如此 完美解決真正意義上的無限輪播圖
嚴禁盜版
轉載請注明出處:https://www.cnblogs.com/bimingcong/p/9028515.html