自動無限輪播廣告欄
自動滑動廣告欄是比較常用的功能之一,方法一是使用的是一個第三方工具AutoScrollViewPager,方法二使用的是自定義控制元件實現需要的要求.
1.AutoScrollViewPager
第三方庫,github地址:
https://github.com/Trinea/android-auto-scroll-view-pager
直接使用線上導包:
compile('cn.trinea.android.view.autoscrollviewpager:android-auto-scroll-view-pager:1.1.2') {
exclude module : 'support-v4'
}
開始使用:
①在佈局中使用控制元件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height ="match_parent"
tools:context="com.simon.autobanner.MainActivity">
<cn.trinea.android.view.autoscrollviewpager.AutoScrollViewPager
android:id="@+id/main_autoscrollviewpager"
android:layout_width="match_parent"
android:layout_height="175dp"/>
</RelativeLayout >
②建立Adapter,繼承PagerAdapter
因為這個控制元件是ViewPager,要用到Adapter(介面卡)來展現資料
Activity程式碼
public class MainActivity extends AppCompatActivity {
private AutoScrollViewPager mAutoscrollViewPager;
private MyViewPagerAdapter mMyViewPagerAdapter;
private ArrayList<ImageView> mImageViews;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
}
private void initData() {
//模擬廣告圖片,一般是從網路後臺獲取
mImageViews = new ArrayList<>();
ImageView img1 = new ImageView(this);
img1.setScaleType(ImageView.ScaleType.FIT_XY);
img1.setImageResource(R.mipmap.mao1);
mImageViews.add(img1);
ImageView img2= new ImageView(this);
img2.setScaleType(ImageView.ScaleType.FIT_XY);
img2.setImageResource(R.mipmap.mao2);
mImageViews.add(img2);
ImageView img3 = new ImageView(this);
img3.setScaleType(ImageView.ScaleType.FIT_XY);
img3.setImageResource(R.mipmap.mao3);
mImageViews.add(img3);
ImageView img4 = new ImageView(this);
img4.setScaleType(ImageView.ScaleType.FIT_XY);
img4.setImageResource(R.mipmap.mao4);
mImageViews.add(img4);
}
private void initView() {
//找到控制元件id
mAutoscrollViewPager = (AutoScrollViewPager) findViewById(R.id.main_autoscrollviewpager);
//new出Adapter
mMyViewPagerAdapter = new MyViewPagerAdapter(this);
//傳入資料
mMyViewPagerAdapter.setDatas(mImageViews);
//繫結ViewPager和adapter
mAutoscrollViewPager.setAdapter(mMyViewPagerAdapter);
//啟動自動滑動
mAutoscrollViewPager.startAutoScroll();
}
}
adapter程式碼
public class MyViewPagerAdapter extends PagerAdapter {
private final Context context;
private ArrayList<ImageView> mDatas;
public MyViewPagerAdapter(Context context) {
this.context = context;
}
public void setDatas(ArrayList<ImageView> imageViews){
mDatas=imageViews;
}
@Override
public int getCount() {
return mDatas.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
//還需要重寫兩個方法instantiateItem和destroyItem
//將某一項檢視新增ViewPager中
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView imageView = mDatas.get(position);
container.addView(imageView);
//返回圖片檢視
return imageView;
}
//將某一項檢視從ViewPager中銷燬
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView imageView = mDatas.get(position);
container.removeView(imageView);
}
}
③新增指示器
/***
* 初始化指示器
*/
private void initAdBannerIndicator(int size) {
//1.做一個for迴圈
//2.建立圖片控制元件 要設定寬高 繫結shapDrawable 新增到容器中
//3.預設讓第一個選中
for (int i = 0; i < size; i++) {
ImageView iv = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(15, 15);//px
params.setMargins(20, 0, 0, 0);
iv.setLayoutParams(params);
iv.setBackgroundResource(R.drawable.ad_indicator_bg);
mAdIndicator.addView(iv);
}
//啟動時預設為第一個
changeAdIndicator(0);
}
/**
* 修改廣告欄的指示器
*/
private void changeAdIndicator(int position) {
int childCount = mAdIndicator.getChildCount();
for (int i = 0; i < childCount; i++) {
//getChildAt 獲取某個容器內部的位置為i的子控制元件
mAdIndicator.getChildAt(i).setSelected(i == position);
}
}
要讓指示器隨著廣告的變化而變化,要給ViewPager設定監聽器,獲取ViewPager當前位置,然後修改指示器,從而達到效果
//找到指示器的容器id
mAdIndicator = (LinearLayout) findViewById(R.id.ad_indicator);
initAdBannerIndicator(mImageViews.size());
//設定監聽器
mAutoscrollViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
changeAdIndicator(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
但是這裡還有一點小問題,就是從最後一頁返回第一頁時,效果不太好,可以通過重寫某個方法達到想要的效果,原理與下面的方法相同,所以這裡就不重複了.
④其他屬性設定
setInterval(long) 設定自動滾動的間隔時間,單位為毫秒
setDirection(int) 設定自動滾動的方向,預設向右
setCycle(boolean) 是否自動迴圈輪播,預設為true
setScrollDurationFactor(double) 設定ViewPager滑動動畫間隔時間的倍率,達到減慢動畫或改變動畫速度的效果
setStopScrollWhenTouch(boolean) 當手指碰到ViewPager時是否停止自動滾動,預設為true
setSlideBorderMode(int) 滑動到第一個或最後一個Item的處理方式,支援沒有任何操作、輪播以及傳遞到父View三種模式
setBorderAnimation(boolean) 設定迴圈滾動時滑動到從邊緣滾動到下一個是否需要動畫,預設為true
2.自定義廣告輪播控制元件
採用自定義控制元件的方法,做出一個能達到想要的效果的廣告輪播控制元件
①建立一個新的類BannerScrollView,繼承RelativeLayout
實現構造方法,並模擬了資料
public BannerScrollView(Context context) {
super(context);
}
public BannerScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
initView();
}
private void initView() {
//因為是繼承了系統的控制元件,所以在載入佈局的時候需要與父佈局繫結
View view = View.inflate(getContext(), R.layout.view_banner, this);
mBannerVp = (ViewPager) view.findViewById(R.id.banner_vp);
mBannerRl = (RelativeLayout) view.findViewById(R.id.banner_rl);
mBannerTvTitle = (TextView) view.findViewById(R.id.banner_tv_title);
mBannerLlIndicator = (LinearLayout) view.findViewById(R.id.banner_ll_indicator);
//建立adapter
mBannerScrollAdapter = new BannerScrollAdapter();
mBannerScrollAdapter.setDatas(mImageViews);
//繫結ViewPager和adapter
mBannerVp.setAdapter(mBannerScrollAdapter);
}
private void initData() {
mImageViews = new ArrayList<>();
//根據業務需求,把傳進來的資料進行網路請求,再轉為圖片格式放入imageView
//現在只能模擬資料,直接放入圖片
ImageView img1 = new ImageView(getContext());
img1.setScaleType(ImageView.ScaleType.FIT_XY);
img1.setImageResource(R.mipmap.mao1);
mImageViews.add(img1);
ImageView img2 = new ImageView(getContext());
img2.setScaleType(ImageView.ScaleType.FIT_XY);
img2.setImageResource(R.mipmap.mao2);
mImageViews.add(img2);
ImageView img3 = new ImageView(getContext());
img3.setScaleType(ImageView.ScaleType.FIT_XY);
img3.setImageResource(R.mipmap.mao3);
mImageViews.add(img3);
ImageView img4 = new ImageView(getContext());
img4.setScaleType(ImageView.ScaleType.FIT_XY);
img4.setImageResource(R.mipmap.mao4);
mImageViews.add(img4);
}
②建立介面卡adapter
public class BannerScrollAdapter extends PagerAdapter {
private ArrayList<ImageView> mBannerImg;
public void setDatas(ArrayList<ImageView> bannerImg) {
mBannerImg = bannerImg;
}
@Override
public int getCount() {
//把數量寫成integer的最大值,這就能實現無限播放了
return Integer.MAX_VALUE;
// return mBannerImg.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
//防止數引越界
position = position % mBannerImg.size();
ImageView imageView = mBannerImg.get(position);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
position = position%mBannerImg.size();
ImageView imageView = mBannerImg.get(position);
container.removeView(imageView);
}
}
現在已經實現了ViewPager的效果,而且能夠無限滑動
③讓廣告自動輪播
讓廣告自動輪播的方法不只一種,我這裡用的是Handler傳送延遲訊息,來進行輪播
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//① int position = msg.what;
②int position=mBannerVp.getCurrentItem();
position++;
mBannerVp.setCurrentItem(position);
sendEmptyMessageDelayed(position, 2000);
}
};
這裡有一個bug,①中position值是從handler傳送過來的mBannerVp.getCurrentItem(),但是如果使用這個值的話,當廣告欄往回滑的時候就會報錯,而使用②中再次獲取mBannerVp.getCurrentItem()值後就可以正常執行.
經過列印log得知,①中的資料不是期望的值,具體的原因可能需要檢視原始碼才能知道.
④新增ViewPager的觸控事件
現在已經實現了廣告的輪播效果,但是現在的程式碼還有很多的問題
1.當你想手動滑動廣告的時候,廣告還是會自動輪播.
2.當你往回滑時,程式會報錯,而且錯誤不只是一個.
給ViewPager新增觸控事件可以暫時解決這兩個問題,讓程式能進行下去,但是有時還是會報錯,暫時還沒找到原因.
mBannerVp.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
//當按下時,停止給handler傳送訊息
case MotionEvent.ACTION_DOWN:
mHandler.removeCallbacksAndMessages(null);
break;
//當鬆開或者手指已經離開ViewPager範圍後,會重新發送訊息,繼續輪播
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mHandler.sendEmptyMessageDelayed(mBannerVp.getCurrentItem(), 1000);
break;
}
return false;
}
});
效果:
⑤最後加上指示器
//初始化指示器
private void initDot() {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(0, 0, 8, 0);
for (int i = 0; i < mImageViews.size(); i++) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.bg_dot_selected);
mBannerLlIndicator.addView(imageView, layoutParams);
}
//從第一個開始
selectDot(0);
}
//改變指示器的顯示,顯示當前位置
private void selectDot(int position) {
int size = mImageViews.size();
position = position % size;
for (int i = 0; i < size; i++) {
ImageView childAt = (ImageView) mBannerLlIndicator.getChildAt(i);
if (position == i) {
childAt.setImageResource(R.drawable.bg_dot);
} else {
childAt.setImageResource(R.drawable.bg_dot_selected);
}
}
}
//設定ViewPager的監聽器,監聽當前pager的位置,並修改指示器位置
mBannerVp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
selectDot(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
完成,最終效果如圖: