Android 輪播圖(Viewpager+Handler定時器)
發現好多人提到banner,第一個想法就是擼個第三方依賴。然後出bug了,開啟三方程式碼,一堆檔案無從下手,改了又擔心出現新bug,然後又替換了第二個三方…
一個ViewPager能實現的功能,何必求助第三方。
Banner的實現技術點主要在於
1 無限迴圈,當banner滑到最後一張後繼續滑動,要滑回第一張
2 自動輪播
Adapter程式碼
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import java.util.List;
/**
* Created by KID on 2017/8/11 0011.
*/
public class PagerBannerAdapter extends PagerAdapter {
private Context context;
private List<String> imgUrls;
private ViewPager mViewPager;
private boolean isPlay=false;
public PagerBannerAdapter(Context context, List<String> imgUrls,ViewPager mViewPager) {
this.context = context;
this .imgUrls = imgUrls;
this.mViewPager=mViewPager;
}
//是否自動播放第一張圖片到第二張
public void setPlayingFirstItem(boolean isPlay){
this.isPlay=isPlay;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
final int pos = position%imgUrls.size();
View view = LayoutInflater.from(context).inflate(R.layout.item_vp, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.img_item);
Glide.with(context).load(imgUrls.get(pos)).into(imageView);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context,"當前看到的要做點選事件的position="+pos+"-----實際position="+position,Toast.LENGTH_SHORT).show();
}
});
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
Log.d("BannerView","destroyItem position======"+position);
}
@Override
public int getCount() {
//理論上當圖片不為1張時,getCount可以設定無窮大,這裡設定成圖片4倍只是想看會不會滑到頭,實際上3倍就夠了,設2倍的話,當圖片只有2張時可能會碰到頭
return imgUrls.size()==1?imgUrls.size():imgUrls.size()*4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//當顯示介面載入完時呼叫該方法
@Override
public void finishUpdate(ViewGroup container) {
Log.d("BannerView","finishUpdate position======"+mViewPager.getCurrentItem());
int position = mViewPager.getCurrentItem();
if(imgUrls.size()==1){
//TODO 但輪播圖片只有一張的時候,什麼都不做,或者隱藏小圓點,提示文字之類。當然,如果你只有一張圖片,你還想重複滑出這張圖片的話,在這裡開始你的騷操作
} else {
//TODO 但輪播圖片超過3張時,每當圖片的position超過圖片數量時,切換viewpager當前選擇item(去除切換動畫效果)
if (position == 0){
position = imgUrls.size();
//TODO 自動輪播的時候,需要這部判斷來讓第一張和第二張平滑過渡
if(!isPlay){
mViewPager.setCurrentItem(position,false);
}
} else if(position>imgUrls.size()+1){
mViewPager.setCurrentItem(position%imgUrls.size(),false);
}
}
}
}
Activity程式碼
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
/**
* Created by KID on 2017/8/16 0016.
* Handler實現圖片自動輪播
*/
public class PlayBannerActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
@Bind(R.id.view_pager)
ViewPager viewPager;
@Bind(R.id.tv_page)
TextView pageTv;
List<String> imgUrls=new ArrayList<>();
PagerBannerAdapter adapter;
private boolean isStill;//是否靜止
int pos ;//看到的position
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_banner);
ButterKnife.bind(this);
initData();
}
private void initData() {
imgUrls.add("http://img2.91.com/uploads/allimg/140417/59-14041GQ2040-L.jpg");
imgUrls.add("http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1205/25/c2/11755122_1337938898578_800x600.jpg");
imgUrls.add("http://img04.tooopen.com/images/20130114/tooopen_22372502.jpg");
imgUrls.add("http://img3.iqilu.com/data/attachment/forum/201308/21/100932s9pwjxmm4h8jy704.jpg");
imgUrls.add("http://images.ali213.net/picfile/pic/2013/02/25/927_48.jpg");
adapter=new PagerBannerAdapter(PlayBannerActivity.this,imgUrls,viewPager);
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(this);
//第一次進入頁面開始輪播圖的間隔要久一點,要等圖片,還有你其他的頁面資料加載出來以後才輪播,提高使用者體驗
mHandler.sendEmptyMessageDelayed(MESSAGE_PLAY_IMAGE,4000);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(positionOffset==0&&positionOffsetPixels==0){
isStill=true;
}else {
isStill=false;
mHandler.removeMessages(MESSAGE_PLAY_IMAGE);
}
}
@Override
public void onPageSelected(int position) {
//列印position為真實的position
pos=position%imgUrls.size();
pageTv.setText(pos+1+"/"+imgUrls.size());
}
@Override
public void onPageScrollStateChanged(int state) {
if(state==0){//靜止
isStill=true;
mHandler.removeMessages(MESSAGE_PLAY_IMAGE);
mHandler.sendEmptyMessageDelayed(MESSAGE_PLAY_IMAGE,PLAY_DELAY);
}
}
/**
* 訊息處理
*/
//輪播下一張圖片
private static final int MESSAGE_PLAY_IMAGE=1001;
//輪播間隔時間
private static final long PLAY_DELAY=2000;
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
/**滑動中,同步播放進度*/
case MESSAGE_PLAY_IMAGE:
if(isStill){
if(pos==0){
adapter.setPlayingFirstItem(true);
viewPager.setCurrentItem(0,false);
viewPager.setCurrentItem(pos+1);
adapter.setPlayingFirstItem(false);
}else {
viewPager.setCurrentItem(pos+1);
adapter.setPlayingFirstItem(false);
}
}
break;
}
}
};
}
核心程式碼
//當顯示介面載入完時呼叫該方法
@Override
public void finishUpdate(ViewGroup container) {
Log.d("BannerView","finishUpdate position======"+mViewPager.getCurrentItem());
int position = mViewPager.getCurrentItem();
if(imgUrls.size()==1){
//TODO 但輪播圖片只有一張的時候,什麼都不做,或者隱藏小圓點,提示文字之類。當然,如果你只有一張圖片,你還想重複滑出這張圖片的話,在這裡開始你的騷操作
} else {
//TODO 但輪播圖片超過3張時,每當圖片的position超過圖片數量時,切換viewpager當前選擇item(去除切換動畫效果)
if (position == 0){
position = imgUrls.size();
//TODO 自動輪播的時候,需要這部判斷來讓第一張和第二張平滑過渡
if(!isPlay){
mViewPager.setCurrentItem(position,false);
}
} else if(position>imgUrls.size()+1){
mViewPager.setCurrentItem(position%imgUrls.size(),false);
}
}
}
將getCount return 無窮大,當圖片顯示在第一張位置(position=0)的時候,我們要讓viewpager左邊也有圖片,所以將position的索引加上圖片數量。其實到這裡,我們就已經能實現圖片無限輪播了,再加上hanlder延遲執行,自動輪播效果就出來了。但position的數量無限增加,item的數量也會一直增加,哪怕viewpager預設只會儲存當前和相鄰兩頁,那些被劃過的pager佔用的記憶體也不會馬上釋放掉。所以我們不能讓position,也就是item無限增加。 ViewPager的切換中,可以設定去除切換效果setCurrentItem(position,false);
而我們需要找準一個時機,讓viewpager切回position最小時的狀態 mViewPager.setCurrentItem(position%imgUrls.size(),false);
handler自動輪播的程式碼就比較簡單了,通過 mHandler.sendEmptyMessageDelayed(MESSAGE_PLAY_IMAGE,PLAY_DELAY);
和mHandler.removeMessages(MESSAGE_PLAY_IMAGE)來實現。當viewpager處於靜止狀態時,丟擲一個延遲 n秒執行的訊息去讓viewpager切換到下一頁,viewpager切換到下一頁後,又會處於靜止狀態,再次丟擲n秒執行的訊息。當延遲訊息執行前,viewpager狀態不是靜止了,就把延遲訊息取消掉。
至此,一個自動輪播的banner就出來了。
可能你看著,感覺程式碼一堆,沒第三方寫起來簡潔- -!
ok,讓我們稍微封裝一下
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import java.util.List;
/**
* Created by KID on 2017/8/17 0017.
*/
public class BannerView extends FrameLayout implements ViewPager.OnPageChangeListener {
//輪播下一張圖片
private static final int MESSAGE_PLAY_IMAGE=1001;
//輪播間隔時間
private static final long PLAY_DELAY=2000L;
//第一張圖片間隔多久開始輪播
private static final long FIRST_DELAY=4000L;
private ViewPager viewPager;
private Context context;
private List<String> imgUrls;
private BannerPageAdapter bannerPageAdapter;
private int cusPosition;//當前看到的選中位置
private boolean isAutoPlay=false;
private BannerListener bannerListener;
public interface BannerListener{
void OnBannerSelect(int position);
void OnBannerClick(int position);
}
public void setBannerListener(BannerListener bannerListener){
this.bannerListener=bannerListener;
}
private boolean isStill;//是否靜止
int pos ;//看到的position
public BannerView(Context context) {
super(context);
this.context=context;
}
public BannerView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context=context;
init(context);
}
public BannerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context=context;
}
/**
* @param isAutoPlay 是否自動播放 ,實現比較暴力,直接不讓handler訊息執行
*/
public void setAutoPlay(boolean isAutoPlay){
this.isAutoPlay=isAutoPlay;
}
/**
* 設定圖片
* @param imageList
*/
public void setImageList(List<String>imageList){
imgUrls=imageList;
bannerPageAdapter=new BannerPageAdapter();
viewPager.setAdapter(bannerPageAdapter);
viewPager.addOnPageChangeListener(this);
//第一次進入頁面開始輪播圖的間隔要久一點,要等圖片,還有你其他的頁面資料加載出來以後才輪播,提高使用者體驗
mHandler.sendEmptyMessageDelayed(MESSAGE_PLAY_IMAGE,FIRST_DELAY);
}
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.view_banner, this);
viewPager= (ViewPager) findViewById(R.id.view_pager);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if(positionOffset==0&&positionOffsetPixels==0){
isStill=true;
}else {
isStill=false;
mHandler.removeMessages(MESSAGE_PLAY_IMAGE);
}
}
@Override
public void onPageSelected(int position) {
//列印position為真實的position
pos=position%imgUrls.size();
if(cusPosition!=pos){//引入自動播放後,會在某一位置做一個無動畫效果的頁面切換,加入這步判斷才回調防止重複呼叫
bannerListener.OnBannerSelect(pos);
}
cusPosition=pos;
}
@Override
public void onPageScrollStateChanged(int state) {
if(state==0){//靜止
isStill=true;
mHandler.removeMessages(MESSAGE_PLAY_IMAGE);
mHandler.sendEmptyMessageDelayed(MESSAGE_PLAY_IMAGE,PLAY_DELAY);
}
}
class BannerPageAdapter extends PagerAdapter {
private boolean isPlay=false;
public BannerPageAdapter() {
}
//是否自動播放第一張圖片到第二張
public void setPlayingFirstItem(boolean isPlay){
this.isPlay=isPlay;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
final int pos = position%imgUrls.size();
View view = LayoutInflater.from(context).inflate(R.layout.item_vp, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.img_item);
Glide.with(context).load(imgUrls.get(pos)).into(imageView);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bannerListener.OnBannerClick(pos);
}
});
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public int getCount() {
// 理論上當圖片不為1張時,getCount可以設定無窮大,這裡設定成圖片4倍只是想看會不會滑到頭,實際上3倍就夠了,設2倍的話,當圖片只有2張時可能會碰到頭
// return Integer.MAX_VALUE;
return imgUrls.size()==1?imgUrls.size():imgUrls.size()*4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//當顯示介面載入完時呼叫該方法
@Override
public void finishUpdate(ViewGroup container) {
Log.d("BannerView","finishUpdate position======"+viewPager.getCurrentItem());
int position = viewPager.getCurrentItem();
if(imgUrls.size()==1){
//TODO 但輪播圖片只有一張的時候,什麼都不做,或者隱藏小圓點,提示文字之類。當然,如果你只有一張圖片,你還想重複滑出這張圖片的話,在這裡開始你的騷操作
} else {
//TODO 但輪播圖片超過3張時,每當圖片的position超過圖片數量時,切換viewpager當前選擇item(去除切換動畫效果)
if (position == 0){
position = imgUrls.size();
//TODO 自動輪播的時候,需要這部判斷來讓第一張和第二張平滑過渡
if(!isPlay){
viewPager.setCurrentItem(position,false);
}
} else if(position>imgUrls.size()+1){
viewPager.setCurrentItem(position%imgUrls.size(),false);
}
}
}
}
/**
* 訊息處理
*/
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
/**滑動中,同步播放進度*/
case MESSAGE_PLAY_IMAGE:
if(isStill&&isAutoPlay){
if(pos==0){
bannerPageAdapter.setPlayingFirstItem(true);
viewPager.setCurrentItem(0,false);
viewPager.setCurrentItem(pos+1);
bannerPageAdapter.setPlayingFirstItem(false);
}else {
viewPager.setCurrentItem(pos+1);
bannerPageAdapter.setPlayingFirstItem(false);
}
}
break;
}
}
};
/**
* 退出頁面後防止handler還執行
*/
public void stopPlay(){
if(mHandler!=null)mHandler.removeMessages(MESSAGE_PLAY_IMAGE);
}
}
使用
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
public class CusBannerActivity extends AppCompatActivity {
@Bind(R.id.bannerView)
BannerView bannerView;
@Bind(R.id.tv_page)
TextView pageTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cus_banner);
ButterKnife.bind(this);
final List<String>list=new ArrayList<>();
list.add("http://img2.91.com/uploads/allimg/140417/59-14041GQ2040-L.jpg");
list.add("http://img.pconline.com.cn/images/upload/upc/tx/wallpaper/1205/25/c2/11755122_1337938898578_800x600.jpg");
list.add("http://img04.tooopen.com/images/20130114/tooopen_22372502.jpg");
list.add("http://img3.iqilu.com/data/attachment/forum/201308/21/100932s9pwjxmm4h8jy704.jpg");
list.add("http://images.ali213.net/picfile/pic/2013/02/25/927_48.jpg");
bannerView.setImageList(list);
bannerView.setAutoPlay(true);
bannerView.setBannerListener(new BannerView.BannerListener() {
@Override
public void OnBannerSelect(int position) {
pageTv.setText(position+1+"/"+list.size());
Toast.makeText(CusBannerActivity.this, "選中======="+position, Toast.LENGTH_SHORT).show();
}
@Override
public void OnBannerClick(int position) {
Toast.makeText(CusBannerActivity.this, "點選======="+position, Toast.LENGTH_SHORT).show();
}
});
pageTv.setText(1+"/"+list.size());
}
@Override
protected void onDestroy() {
super.onDestroy();
bannerView.stopPlay();
}
}
在onDestory裡,我們需要讓hanlder不再執行。PS,有些手機退出介面後,onDestory遲遲不執行,這時候就要結合實際情況,在onPause或者監聽返回鍵,你自己專案的返回按鈕執行bannerView.stopPlay()這步操作了。很多三方庫封裝的banner,定時器沒有關閉操作,在頁面finish後,延遲執行的操作裡,找不到之前被關閉頁面的view,導致App崩潰。
相關推薦
Android 輪播圖(Viewpager+Handler定時器)
發現好多人提到banner,第一個想法就是擼個第三方依賴。然後出bug了,開啟三方程式碼,一堆檔案無從下手,改了又擔心出現新bug,然後又替換了第二個三方… 一個ViewPager能實現的功能,何必求助第三方。 Banner的實現技術點主要在於 1
JQ輪播圖(多張同時顯示)
HTML: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <
js面向物件---無縫輪播圖(附面向過程程式碼)
window.onload = function(){ var t1 = new Lb("box"); t1.l(); //設定包含圖片的ul寬度 t1.dot(); //點哪個圓,相對應的圖片顯示
自定義ViewGroup和FrameLayout實現輪播圖(包括底部小圓點)
廣告輪播圖在現在的APP首頁比較常見,主要的實現方式有兩種,一種是通過ViewPager,一種是通過自定義ViewGroup。前者的實現方式比較簡便,本篇文章講的是第二種方法,有人說用ViewPager不是更方便嗎,的確,但是我們通過自己定義ViewGroup,
Android 輪播圖 實現 一 :三方框架 自定義viewPager (CircleViewPager.)實現無限輪播。
使用流程:1 。 gradle中新增依賴compile 'com.zhpan.library:viewpager:1.0.3'2.在xml檔案中新增如下程式碼:<com.zhpan.viewpager.view.CircleViewPager andr
android banner卡片式輪播圖之recyclerView橫向定時滑動
使用環境: 使用首頁banner輪播圖,卡片式輪播 使用效果: 使用方法:
TabLayout + ViewPager輪播圖 (雙層巢狀),側拉展示條目(頭像加listview,點選頭像可切換)PullToRefreshListView重新整理載入
模組簡介: 1.底部:TabLayout + ViewPager輪播圖 2.主頁面可測拉 展示頭像,可選擇系統相簿,切換圖片(二級取樣) 3.TabLayout + ViewPager巢狀TabLayout + ViewPager以展示 正在上映 和 *
Android框架之路——Banner實現輪播圖(RecyclerView新增Header)
一、簡介 Banner能實現迴圈播放多個廣告圖片和手動滑動迴圈等功能。因為原生ViewPager並不支援迴圈翻頁, 要實現迴圈還得需要自己去動手。Banner框架可以進行不同樣式、不同動畫設定, 以及完善的api方法能滿足大部分軟體首頁輪播圖效果的需求。
android輪播圖簡單實現(左右無限滑動,自動輪播)
直接上程式碼了,都有註釋,原理很簡單 public class MainActivity extends AppCompatActivity { private static final String Tag = MainActivity.class.getSimpleName();
ViewPager打造輪播圖(Banner)\引導頁(Guide)
前言 今年7月時,在Github釋出了一個開源的Banner庫,雖然Star不多,但還是有少部分人使用。 Banner效果: 昨天,有使用此庫的同學提出需求,想在引導頁的時候用這個庫並且最後一頁有進入按鈕如何實現,為滿足他的需求,也方便更多開發者是
輪播圖(一)
left margin font ges opacity onload rgb absolut pin <style> *{ margin:0; padding:0; list-style:none; } .box{ width:520px; height:
Android 輪播圖
網址 ott not 設置 amp 文件添加 .cn ive create package com.example.carson_ho.android_banner;import android.os.Bundle;import android.support.v7.app
vue慕課網音樂項目手記:5-手寫滾動輪播圖(上)
flow overflow box cor 慕課 efs PE osi 通過 在這一節,會封裝一些公用的函數來添加classname,改變image的寬度。 具體如下: 首先:封裝一個slider的組件 <template> <div cl
11.輪播圖(練習)
current cor ext 技術 one 練習 func children script 效果圖: 源代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset
Android輪播圖Banner
Android實現輪播圖 昨天早睡,今天早上精力充沛!所以寫一篇部落格記錄一下。 效果圖: 第一步新增依賴: compile 'com.youth.banner:banner:1.4.9' 第二步在佈局中新增: <com.youth.banner.Banner
關於輪播圖(1)
不瞞大家說,輪播圖簡直是我的噩夢,就像是論文之於大學生[受虐滑稽][受虐滑稽] 簡單輪播圖 最簡單的輪播圖,用WebAPI做的,點選圖片底下的數字跳轉到相對應的圖片。 1、首先把結構寫出來 <div class="box" id="box"> <div
完整輪播圖(4)
我們終於迎來了最完整的輪播圖 當然還是WebAPI做的 依舊和之前一樣,結構樣式只給程式碼,script裡面會有一些註釋 有的圖片路徑可能會報錯什麼的,因為我本來使用的是本地圖片,然後換成了臨時百度的圖片,圖片路徑出錯了你們要自己換圖片,反正是不要指望我了,嘻嘻 一、結構 <d
無縫滾動輪播圖(3)
我吃了炫邁做出來的輪播圖,停不下來的那種 一、結構 <div class="box" id="screen"> <ul> <li><img src="http://img.mp.itc.cn/upload/20161107/033
左右焦點輪播圖(2)
顧名思義, 這個輪播圖只有左右兩個焦點,只能左右滑動。 一、結構 <div id="box" class="all"> <div class="ad"> <ul id="imgs"> <li><img src="
Android 輪播圖Banner切換圖片的效果
Android XBanner使用詳解 2018年03月14日 08:19:59 AND_Devil 閱讀數:910 前言:現如今的很多APP都