教你打造廣告位的循環播放


轉載請標明出處:
http://blog.csdn.net/hai_qing_xu_kong/article/details/50858492
本文出自:【顧林海的博客】

前言

最近剛把駕校的科目一考完,也有充足的時間去研究android,目前自己的打算是這樣的,先從自定義控件開始一步一步的學習研究,之后會去寫一些設計模式之類的文章,到時候歡迎大家來瀏覽。
‘廣告位’這個詞匯大家一定不陌生,現在大部分的APP都會有廣告位,打開某款APP,首頁頂部就會出現一直自動播放的廣告,這種效果還是挺炫的,那如何實現這個功能呢,這篇文章將會揭曉廣告位的神秘面紗。

今天實現的效果是這樣的:

廣告位

打造廣告位的前奏

在開始敲代碼前,先來看看這個廣告位到底應該怎樣實現,從效果圖看我們發現廣告位有以下特點:

  • 廣告位可以自動輪播的。
  • 廣告位是可以向右無限輪播的。
  • 廣告位底部有一個指示器(三個小圓圈),指示器內的圓點個數是按圖片的個數來設定的。
  • 切換到哪個圖片,底下的指示器也切到相應的位置。

廣告位可以自動輪播的

廣告位可以自動輪播的,自動輪播意味着我們需要一個定時器,如何實現定時器,有三種方式:

  1. Handler+Thread
  2. Handler類自帶的postDelyed
  3. Handler+Timer+TimerTask

這三種方式效果都一樣,我用的是第二種:Handler類自帶的postDelyed

private Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// 開啟輪播
switchItem();
handler.postDelayed(this, 1000);
}
};
/**
* 開啟輪播
*/

public void start() {
handler.postDelayed(runnable, 2000);
}

/**
* 關閉輪播
*/

public void stop() {
handler.removeCallbacks(runnable);
}

代碼非常的easy,間隔1秒的輪播。

廣告位是可以向右無限輪播的

這里面實現廣告位的控件,我是選用Gallery控件,通過為Gallery綁定相應的適配器,我們就能通過手指來回切換圖片,那如何無限向右輪播的呢?Gallery通過綁定適配器,自定義適配器時,我們要創建一個繼承BaseAdapter的類,重寫里面的幾個方法,看到有個getCount方法,它主要要來告訴Gallery有多少個Item,這時可以這樣改動:

        @Override
public int getCount() {
final int count = mAdvertisementObjectList == null ? 0
: mAdvertisementObjectList.size();
return count > 1 ? Integer.MAX_VALUE : count;
}

將顯示的Item數改為Integer.MAX_VALUE。

廣告位指示器實現

從效果圖能看到底部居中有個指示器,指示器的圓點個數是可控,這里是通過自定義View來實現的,通過繪制圖片數的圓點。具體代碼如下:

package com.example.advertisementproject.view;

import com.example.advertisementproject.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout.LayoutParams;

/**
* 指示器
*
* @author Linhai Gu
*/

public class IndicatorView extends View {

private LayoutParams mParams;
/**
* 選中的圖標
*/

private Bitmap mSelectorIcon;
/**
* 未選中的圖標
*/

private Bitmap mUnselectorIcon;
/**
* 畫筆
*/

private Paint mPaint;
/**
* 圖標個數
*/

private int mCount;

/**
* 當前高亮顯示圓點的位置
*/

private int mSelectedIndex;

/**
* 圓點的寬度
*/

private int mIconWidth;
/**
* 圓點的高度
*/

private int mIconHeight;

/**
* 指示器的寬度
*/

private int mWidth;

/**
* 指示器的高度
*/

private int mHeight;

/**
* 圓點間的空隔
*/

private int mSpace;

public IndicatorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}

public IndicatorView(Context context) {
super(context);
init(context);
}

private void init(Context _context) {
/**
* 創建畫筆
*/

mPaint = new Paint();
/**
* 獲取選中圖標的bitmap
*/

mSelectorIcon = BitmapFactory.decodeResource(_context.getResources(),
R.drawable.selector_point);
/**
* 獲取未選中圖標的bitmap
*/

mUnselectorIcon = BitmapFactory.decodeResource(_context.getResources(),
R.drawable.unselector_point);
mIconWidth = mUnselectorIcon.getWidth();
mIconHeight = mUnselectorIcon.getHeight();
mParams = new LayoutParams(LayoutParams.WRAP_CONTENT, mIconHeight);
setLayoutParams(mParams);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawSelectIcon(mSelectedIndex, canvas);
}

/**
* 繪制圖標
*
* @param _select
* @param _canvas
*/

private void drawSelectIcon(int _select, Canvas _canvas) {
for (int i = 0; i < mCount; i++) {
if (i == _select) {
/**
* 被選中的當前顯示的指示器圓點
*/

drawSelectedIcon(i, _canvas);
} else {
/**
* 未選中時的指示器圓點
*/

drawUnselectedIcon(i, _canvas);
}
}
}

/**
* 繪制選中時的圓點
*
* @param _index
* @param _canvas
*/

private void drawSelectedIcon(int _index, Canvas _canvas) {
_canvas.drawBitmap(mSelectorIcon, _index * (mIconWidth + mSpace), 0,
mPaint);
}

/**
* 繪制未選中時的圓點
*
* @param _index
* @param _canvas
*/

private void drawUnselectedIcon(int _index, Canvas _canvas) {
_canvas.drawBitmap(mUnselectorIcon, _index * (mIconWidth + mSpace), 0,
mPaint);
}

/**
* 指示器圓點的總個數
*
* @param _count
* 總數
*
*/

public void setTotal(int _count) {
this.mCount = _count;
this.setLayoutParams(mParams);
if (_count == 0) {
this.setVisibility(View.INVISIBLE);
} else {
mWidth = mIconWidth * _count + (_count - 1) * mSpace;
mHeight = mIconWidth;
this.setVisibility(View.VISIBLE);
}
}

/**
* 選中的圓點的位置
*
* @param _selected
* 高亮圓點位置
*/

public void setSelected(int _selected) {
mSelectedIndex = _selected;
invalidate();
}

/**
* 設置圓點間的空隔
*
* @param _space
*/

public void setSpace(int _space) {
this.mSpace = _space;
}

/**
* 獲取指示器寬度
*
* @return
*/

public int getIndicatorWidth() {
return mWidth;
}

}

繪制圓點時,我們要把握好繪制的位置,drawBitmap有以下幾個參數:

public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) 

bitmap是我們要繪制的圓點
left是距離屏幕左邊的距離
top是距離頂部的距離
paint是我們定義的畫筆

圓點與圓點有空隔,如果有兩個圖片的話,就有一個空隔,三個圖片的話就有兩個空隔,因此整個指示器的寬度就可以計算出來:指示器寬度=圓點自身寬度*圓點總數+(圓點總數-1)間隔的距離。

mWidth = mIconWidth * _count + (_count - 1) * mSpace;

怎樣確定繪制圓點的位置,比如要繪制第一個位置的圓點,這時距離左邊距離應該是(這里的起始位置從0開始): 0*(繪制圓點的寬度+空隔)=0,也就是在0,0位置繪制;如果是繪制第二個位置:1*(繪制圓點的寬度+空隔),這樣依次類推,兩圓點繪制的距離是圓點寬度加上空隔的距離。

    /**
* 繪制選中時的圓點
*
* @param _index
* @param _canvas
*/

private void drawSelectedIcon(int _index, Canvas _canvas) {
_canvas.drawBitmap(mSelectorIcon, _index * (mIconWidth + mSpace), 0,
mPaint);
}

/**
* 繪制未選中時的圓點
*
* @param _index
* @param _canvas
*/

private void drawUnselectedIcon(int _index, Canvas _canvas) {
_canvas.drawBitmap(mUnselectorIcon, _index * (mIconWidth + mSpace), 0,
mPaint);
}

(正餐)打造廣告位

創建我們的AdvertisementView並繼承RelativeLayout,在這里加載我們的廣告位的布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_group"
android:layout_width="match_parent"
android:layout_height="wrap_content" >


<Gallery
android:id="@+id/gl_images"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />


<LinearLayout
android:id="@+id/ll_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="4dp"
android:orientation="horizontal" >


<com.example.advertisementproject.view.IndicatorView
android:id="@+id/view_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" >

</com.example.advertisementproject.view.IndicatorView>

</LinearLayout>

</RelativeLayout>

布局的效果就是將指示器放在底部,居中操作我們放在代碼中實現,這時因為我們要獲取指示器的寬度,通過屏幕寬度/2-(指示器寬度/2)得到指示器放置的起始位置。

整體的代碼比較簡單,一下是整個廣告位輪播的源碼:

package com.example.advertisementproject.view;

import java.util.ArrayList;

import com.example.advertisementproject.R;
import com.example.advertisementproject.view.entity.AdvertisementObject;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

/**
* 廣告位輪播
*
* @author Linhai Gu
*
*/

public class AdvertisementView extends RelativeLayout implements
OnItemClickListener, OnItemSelectedListener {


private Context mContext;

public final int ADVER_HEIGHT = 50;

/**
* 指示器容器
*/

private LinearLayout ll_group;
/**
* 指示器
*/

private IndicatorView mIndicatorView;
private RelativeLayout rl_group;

/**
* 廣告圖寬度
*/

private float mWidth;

/**
* 廣告圖的高度
*/

private int mHeight;

private Gallery mGallery;

private ImageSwitcherAdapter mImageSwitcherAdapter;

/**
* 數據源
*/

private ArrayList<AdvertisementObject> mAdvertisementObjectList = new ArrayList<AdvertisementObject>();
/**
* 是不是本地資源ID
*/

private boolean isResourceId;
private int mMax;

private OnItemClickListener mOnItemClickListener;

public AdvertisementView(Context context) {
this(context, null);
}

public AdvertisementView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public AdvertisementView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
initData();
initView();
initAdapter();
initEvent();
}

/**
* 數據初始化
*/

private void initData() {
WindowManager windowManager = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics metric = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metric);
mWidth = metric.widthPixels;
}

/**
* 初始化View
*/

private void initView() {
View rootView = LayoutInflater.from(mContext).inflate(
R.layout.advertisement_view_layout, this);
ll_group = (LinearLayout) rootView.findViewById(R.id.ll_group);
mGallery = (Gallery) rootView.findViewById(R.id.gl_images);
rl_group = (RelativeLayout) rootView.findViewById(R.id.rl_group);
mIndicatorView = (IndicatorView) rootView
.findViewById(R.id.view_indicator);
/*
* 設置圓點間隔距離
*/

mIndicatorView.setSpace(6);
LayoutParams params = new LayoutParams(new LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, mHeight));
this.setLayoutParams(params);
}

private void setLayoutParams() {
LayoutParams params = new LayoutParams(new LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, mHeight));
rl_group.setLayoutParams(params);
}

/**
* 給廣告空間綁定適配器
*/

private void initAdapter() {
mImageSwitcherAdapter = new ImageSwitcherAdapter();
mGallery.setAdapter(mImageSwitcherAdapter);
}

private void initEvent() {
mGallery.setOnItemClickListener(this);
mGallery.setOnItemSelectedListener(this);
}

/**
* 設置圖片大小
*
* @param imageView
*/

private void setPxImage(ImageView imageView) {
android.view.ViewGroup.LayoutParams lp;
lp = imageView.getLayoutParams();
lp.height = mHeight;
lp.width = (int) mWidth;
imageView.setLayoutParams(lp);
}

public class ImageSwitcherAdapter extends BaseAdapter {

@Override
public int getCount() {
final int count = mAdvertisementObjectList == null ? 0
: mAdvertisementObjectList.size();
return count > 1 ? Integer.MAX_VALUE : count;
}

@Override
public Object getItem(int position) {
mAdvertisementObjectList.get(position % mMax);
return null;
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(
R.layout.advertisement_item_layout, null);
viewHolder.iv_image = (ImageView) convertView
.findViewById(R.id.iv_image);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
AdvertisementObject advertisementObject = mAdvertisementObjectList
.get(position % mMax);
setPxImage(viewHolder.iv_image);
if (isResourceId) {
/**
* 從本地加載
*/

viewHolder.iv_image
.setImageResource(advertisementObject.mResourceId);
} else {
/**
* 從網絡加載
*/


}

return convertView;
}
}

static class ViewHolder {
ImageView iv_image;
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
mOnItemClickListener.onItemClick(position % mMax);
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position,
long id) {
Log.i("TAG", "position:" + position);
mIndicatorView.setSelected(position % mMax);
}

@Override
public void onNothingSelected(AdapterView<?> parent) {

}

/**
* 設置指示器位置
*/

private void setIndicatorParams() {
LayoutParams params = (LayoutParams) ll_group.getLayoutParams();
params.leftMargin = (int) (mWidth / 2 - mIndicatorView.getWidth() / 2);
ll_group.setLayoutParams(params);
}

public interface OnItemClickListener {
void onItemClick(int position);
}

protected void switchItem() {
mGallery.onScroll(null, null, 1, 0);
mGallery.onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);
}

private Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
// 開啟輪播
switchItem();
handler.postDelayed(this, 1000);
}
};

// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

/**
* 設置數據 如果是圖片的URL的話,_isResourceId為false
*
* @param data
* @param _isResourceId
* true:本地圖片資源ID false:網絡圖片URL
*/

public void setData(ArrayList<AdvertisementObject> _data,
boolean _isResourceId) {
this.mAdvertisementObjectList = _data;
this.isResourceId = _isResourceId;
mMax = mAdvertisementObjectList == null ? 0 : mAdvertisementObjectList
.size();
// 設置指示器
mIndicatorView.setTotal(mMax);
setIndicatorParams();
mImageSwitcherAdapter.notifyDataSetChanged();
}

/**
* 設置廣告圖的寬高比例
*
* @param width
* @param height
*/

public void setAdvertisementRate(float width, float height) {
mHeight = (int) ((mWidth / (width + height)) * height);
setLayoutParams();
}

/**
* 開啟輪播
*/

public void start() {
handler.postDelayed(runnable, 2000);
}

/**
* 關閉輪播
*/

public void stop() {
handler.removeCallbacks(runnable);
}

public void setOnItemClickListener(OnItemClickListener _onItemClickListener) {
this.mOnItemClickListener = _onItemClickListener;
}

}

整體流程是這樣的,初始化我們的View,為我們的Gallery綁定適配器,並監聽點擊事件與選中事件,這樣方便回調,接着定義我們的定時器,這里傳遞數據源我寫了一個方法:

    /**
* 設置數據 如果是圖片的URL的話,_isResourceId為false
*
* @param data
* @param _isResourceId
* true:本地圖片資源ID false:網絡圖片URL
*/

public void setData(ArrayList<AdvertisementObject> _data,
boolean _isResourceId) {
this.mAdvertisementObjectList = _data;
this.isResourceId = _isResourceId;
mMax = mAdvertisementObjectList == null ? 0 : mAdvertisementObjectList
.size();
// 設置指示器
mIndicatorView.setTotal(mMax);
setIndicatorParams();
mImageSwitcherAdapter.notifyDataSetChanged();
}

_isResourceId是用於區分是網絡加載還是本地的資源ID,這樣的原因是方便測試,因為通過網絡加載圖片不是本篇的重點,我在AdvertisementObject里放了兩個參數,分別是資源ID,和通過網絡加載的圖片URL:

public class AdvertisementObject implements Serializable {
public String mImageUrl;// 圖片url
public int mResourceId;//本地圖片資源ID
}

當然你也可以加上更多的信息,完全取決於業務需求。

最后看看如何使用這個廣告控件:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<com.example.advertisementproject.view.AdvertisementView
android:id="@+id/view_advertisement"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.example.advertisementproject.view.AdvertisementView>

</LinearLayout>
package com.example.advertisementproject;

import java.util.ArrayList;

import com.example.advertisementproject.view.AdvertisementView;
import com.example.advertisementproject.view.AdvertisementView.OnItemClickListener;
import com.example.advertisementproject.view.entity.AdvertisementObject;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends Activity {

private AdvertisementView mAdvertisementView;
private ArrayList<AdvertisementObject> advertisementObjects = new ArrayList<AdvertisementObject>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initViews();
initEvent();
}

private void initData() {
AdvertisementObject advertisementObject = new AdvertisementObject();
advertisementObject.mResourceId = R.drawable.image1;
advertisementObjects.add(advertisementObject);
advertisementObject = new AdvertisementObject();
advertisementObject.mResourceId = R.drawable.image2;
advertisementObjects.add(advertisementObject);
advertisementObject = new AdvertisementObject();
advertisementObject.mResourceId = R.drawable.image3;
advertisementObjects.add(advertisementObject);
}

private void initViews() {
mAdvertisementView = (AdvertisementView) findViewById(R.id.view_advertisement);
mAdvertisementView.setAdvertisementRate(2, 1);
mAdvertisementView.setData(advertisementObjects, true);
mAdvertisementView.start();
}

private void initEvent() {
mAdvertisementView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(int position) {
Toast.makeText(MainActivity.this, "position:" + position,
Toast.LENGTH_SHORT).show();
}
});
}

@Override
protected void onPause() {
mAdvertisementView.stop();
super.onPause();
}

@Override
protected void onDestroy() {
mAdvertisementView.stop();
super.onDestroy();
}

}

用法是不是很簡單,基於上面的思路,大家能做出更炫的廣告控件(最近寫下一些自定義控件,主要是為了分享自定義控件的一個思路,希望大家喜歡。)

以下是完整的github項目地址
github項目源碼地址:點擊【項目源碼】


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com