新项目一个,不过又是首页广告栏组件,第三次写这个组件了。虽然也可以拷贝以前的代码整理一下完成任务,但还是打算封装一下,重构一下代码,也算是自己近段时间学习的一个检验吧。不错不错~~
先上效果图(其中第三幅图是单击后的跳转页面,也是本人的博客,做下广告哈!):
自定义类AdGallery,继承自Gallery:
package com.wly.android.widget;
import java.util.Timer;
import java.util.TimerTask;
import com.wly.android.widget.AdGalleryHelper.OnGallerySwitchListener;
import net.tsz.afinal.FinalBitmap;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
/**
* 无限滚动广告栏组件 持有自身容器布局引用,可以操作滚动指示器RadioGroup和标题TextView
*
* @author wly
* @date 2013-12-13
*/
public class AdGallery extends Gallery implements
android.widget.AdapterView.OnItemClickListener,
android.widget.AdapterView.OnItemSelectedListener, OnTouchListener {
private Context mContext;
private int mSwitchTime; // 图片切换时间
private boolean runflag = false;
private Timer mTimer; // 自动滚动的定时器
private OnGallerySwitchListener mGallerySwitchListener;
private Advertising[] mAds;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int position = getSelectedItemPosition();
if (position >= (getCount() - 1)) {
setSelection(getCount() / 2, true); // 跳转到第二张图片,在向左滑动一张就到了第一张图片
onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, null);
} else {
onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);
}
}
};
public AdGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mContext = context;
mTimer = new Timer();
}
public AdGallery(Context context) {
super(context);
this.mContext = context;
mTimer = new Timer();
}
public AdGallery(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
mTimer = new Timer();
}
class ViewHolder {
ImageView imageview;
}
/**
* 初始化配置参数
*
* @param ads
* 图片数据数组
* @param switchTime
* 图片切换间隔
* @param l_margin_p
* 图片到距离屏幕左边界距离占屏幕的"比例"
* @param t_margin_p
* 图片到距离屏幕上边界距离占屏幕的"比例"
* @param w_percent
* 图片占屏幕的宽度"比例"
* @param h_percent
* 图片占屏幕的高度"比例"
*/
public void init(Advertising[] ads, int switchTime,
OnGallerySwitchListener gallerySwitchListener) {
this.mSwitchTime = switchTime;
this.mGallerySwitchListener = gallerySwitchListener;
this.mAds = ads;
setAdapter(new AdAdapter());
this.setOnItemClickListener(this);
this.setOnTouchListener(this);
this.setOnItemSelectedListener(this);
this.setSoundEffectsEnabled(false);
// setSpacing(10); //不能包含spacing,否则会导致onKeyDown()失效!!!
setSelection(getCount() / 2); // 默认选中中间位置为起始位置
setFocusableInTouchMode(true);
}
class AdAdapter extends BaseAdapter {
@Override
public int getCount() {
return mAds.length * (Integer.MAX_VALUE / mAds.length);
}
@Override
public Object getItem(int position) {
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) {
convertView = LayoutInflater.from(mContext).inflate(
R.layout.adgallery_image, null);
Gallery.LayoutParams params = new Gallery.LayoutParams(
Gallery.LayoutParams.FILL_PARENT,
Gallery.LayoutParams.WRAP_CONTENT);
convertView.setLayoutParams(params);
viewHolder = new ViewHolder();
viewHolder.imageview = (ImageView) convertView
.findViewById(R.id.gallery_image);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
FinalBitmap.create(mContext).display(viewHolder.imageview,
mAds[position % mAds.length].getPicURL(),
viewHolder.imageview.getWidth(),
viewHolder.imageview.getHeight(), null, null);
return convertView;
}
}
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
int kEvent;
if (isScrollingLeft(e1, e2)) { // 检查是否往左滑动
kEvent = KeyEvent.KEYCODE_DPAD_LEFT;
} else { // 检查是否往右滑动
kEvent = KeyEvent.KEYCODE_DPAD_RIGHT;
}
onKeyDown(kEvent, null);
return true;
}
private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) {
return e2.getX() > (e1.getX() + 50);
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
return super.onScroll(e1, e2, distanceX, distanceY);
}
/**
* 开始自动滚动
*/
public void startAutoScroll() {
mTimer.schedule(new TimerTask() {
public void run() {
if (runflag) {
Message msg = new Message();
if (getSelectedItemPosition() < (getCount() - 1)) {
msg.what = getSelectedItemPosition() + 1;
} else {
msg.what = 0;
}
handler.sendMessage(msg);
}
}
}, mSwitchTime, mSwitchTime);
}
public void setRunFlag(boolean flag) {
runflag = flag;
}
public boolean isAutoScrolling() {
if (mTimer == null) {
return false;
} else {
return true;
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_UP == event.getAction()
|| MotionEvent.ACTION_CANCEL == event.getAction()) {
// 重置自动滚动任务
setRunFlag(true);
} else {
// 停止自动滚动任务
setRunFlag(false);
}
return false;
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int position,
long arg3) {
mGallerySwitchListener.onGallerySwitch(position % (mAds.length));
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
}
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
Intent i = new Intent();
i.setClass(mContext, MyWebViewActivity.class);
i.putExtra("url", mAds[position % mAds.length].getLinkURL());
mContext.startActivity(i);
}
}
以上代码核心就是用一个定时器Timer不断的发送Message个一个Handler,在Handler的handleMessage()方法中手动的切换Gallery组件,有两点需要注意:
1、gallery不能包含spacing属性,即使将该属性设置为0dp也不行,否则会导致onKeyDown()事件失效。另外不要使用setSelection(),因为使用setSelection()只是实现的切换,但没有动画效果。
2、广告栏下方标题必须指定最大长度为一个固定值,否则会在自动切换时发生抖动,这是笔者遇到的一个问题。
再对其进行一个简单的封装(添加一个标题TextView和RadioGroup),新建类AdGalleryHelper:
package com.wly.android.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.LayoutInflater;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.RelativeLayout.LayoutParams;
/**
* 对自定义组件AdGallery进行了一次封装
* 包含对图片标题和当前位置指示器(RadioGroup)的操作
* @author wly
*
*/
public class AdGalleryHelper {
private AdGallery mAdGallery; //无限滚动Gallery
private TextView mPicTitle; //广告图片标题
private RadioGroup mRadioGroup; //滚动标记组件
private Context mContext;
private LayoutInflater mInflater;
RelativeLayout galleryLayout;
public AdGalleryHelper(Context context,final Advertising[] ads,int switchTime) {
this.mContext = context;
mInflater = LayoutInflater.from(context);
galleryLayout = (RelativeLayout)mInflater.inflate(R.layout.adgallery_hellper, null);
mRadioGroup = (RadioGroup)galleryLayout.findViewById(R.id.home_pop_gallery_mark);
//添加RadioButton
Bitmap b = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.point_1);
LayoutParams params = new LayoutParams(
Util.dpToPx(mContext, b.getWidth()),
Util.dpToPx(mContext, b.getHeight()));
for (int i = 0; i < ads.length; i++) {
RadioButton _rb = new RadioButton(mContext);
_rb.setId(0x1234 + i);
_rb.setButtonDrawable(mContext.getResources().getDrawable(
R.drawable.gallery_selector));
mRadioGroup.addView(_rb, params);
}
mPicTitle = (TextView)galleryLayout.findViewById(R.id.news_gallery_text);
mAdGallery = (AdGallery)galleryLayout.findViewById(R.id.gallerypop);
mAdGallery.init(ads, switchTime,new OnGallerySwitchListener() {
@Override
public void onGallerySwitch(int position) {
if (mRadioGroup != null) {
mRadioGroup.check(mRadioGroup.getChildAt(
position).getId());
}
if(mPicTitle != null) {
mPicTitle.setText(ads[position].getTitle());
}
}
});
}
/**
* 向外开放布局对象,使得可以将布局对象添加到外部的布局中去
* @return
*/
public RelativeLayout getLayout() {
return galleryLayout;
}
/**
* 开始自动循环切换
*/
public void startAutoSwitch() {
mAdGallery.setRunFlag(true);
mAdGallery.startAutoScroll();
}
public void stopAutoSwitch() {
mAdGallery.setRunFlag(true);
}
/**
* 图片切换回调接口
* @author wly
*
*/
interface OnGallerySwitchListener {
public void onGallerySwitch(int position);
}
}
实体类Advertising:
package com.wly.android.widget;
/**
* 广告实体类
* @author wly
*
*/
public class Advertising {
private String picURL; //图片地址
private String linkURL; //单击跳转地址
private String title; //标题
public Advertising(String picURL, String linkURL, String title) {
super();
this.picURL = picURL;
this.linkURL = linkURL;
this.title = title;
}
public String getPicURL() {
return picURL;
}
public void setPicURL(String picURL) {
this.picURL = picURL;
}
public String getLinkURL() {
return linkURL;
}
public void setLinkURL(String linkURL) {
this.linkURL = linkURL;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
Activity界面类MainActivity:
package com.wly.android.widget;
import java.io.File;
import net.tsz.afinal.FinalBitmap;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
public class MainActivity extends Activity {
RelativeLayout galleryContainer; //滚动广告组件的容器
LayoutInflater inflater;
AdGalleryHelper mGalleryHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
//============初始化缓存路径,以及AfinalBitmap的初始化,可以忽略
String cacheDir;
if (android.os.Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED)) {
File f = this.getApplicationContext().getExternalCacheDir();
if (null == f) {
cacheDir = Environment.getExternalStorageDirectory().getPath()
+ File.separator + this.getApplicationContext().getPackageName()
+ File.separator + "cache";
} else {
cacheDir = f.getPath();
}
} else {
File f = this.getApplicationContext().getCacheDir();
cacheDir = f.getPath();
}
FinalBitmap.create(this, cacheDir + File.separator
+ "images" + File.separator,
0.3f, 1024 * 1024 * 10,
10);
//==================
//构造测试数据
Advertising ad1 = new Advertising("https://img-my.csdn.net/uploads/201312/14/1386989803_3335.PNG"
, "http://blog.csdn.net/u011638883/article/details/17302293"
, "双向搜索");
Advertising ad2 = new Advertising("https://img-my.csdn.net/uploads/201312/14/1386989613_6900.jpg"
, "http://blog.csdn.net/u011638883/article/details/17245371"
, "创意设计");
Advertising ad3 = new Advertising("https://img-my.csdn.net/uploads/201312/14/1386989802_7236.PNG"
, "http://blog.csdn.net/u011638883/article/details/17248135"
, "Artificial Intelligence");
Advertising[] ads = {ad1,ad2,ad3};
//将AdGalleryHelper添加到布局文件中
galleryContainer = (RelativeLayout) this
.findViewById(R.id.home_gallery);
mGalleryHelper = new AdGalleryHelper(this, ads, 5000);
galleryContainer.addView(mGalleryHelper.getLayout());
//开始自动切换
mGalleryHelper.startAutoSwitch();
}
@Override
protected void onDestroy() {
super.onDestroy();
mGalleryHelper.stopAutoSwitch();
}
}
注意,代码中异步加载图片使用的Afinal框架的FinalBitmap。读者可以根据自己项目加以替换。
代码工程:http://download.csdn.net/detail/u011638883/6713923
用到的Afinal库:http://download.csdn.net/detail/u011638883/6726339
好了,就这样,,
谢谢!!
update(2013-12-17):补上项目中的Afinal框架代码,之前上传了5、6次都失败,,