前几天看到淘宝和易迅的客户端的广告栏做的不错,今天就尝试了一下,模仿着写了带指引的ViewFlipper。本文主要介绍指引栏的实现,论坛上关于ViewFlipper的使用和介绍很多,就不过多介绍。
效果图如下:
首先是布局,稍有Android开发经验的人很容易看出来,这是一个Layout里面嵌套了ViewFliper和一个LinearLayout。布局如下:
<RelativeLayout
android:id="@+id/food_recom_viewfliper_rl"
android:layout_width="fill_parent"
android:longClickable="true"
android:layout_height="150dp">
<com.mobsut.mm.widget.GestureViewFliper
android:id="@+id/food_recom_viewfliper"
android:layout_height="150dp"
android:background="@color/white"
android:layout_width="fill_parent"/>
<LinearLayout
android:id="@+id/food_recom_page_indicator"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:orientation="horizontal"
android:padding="@dimen/offset_2dp"></LinearLayout>
</RelativeLayout >
可以看到这个GestureViewFliper是我自定义的,继承于VIewFlipper,实现OnGestureListener接口用来识别用户手势,让用户可以手动滑动广告栏。在用GestureDetector 识别手势时,会出现一个问题:onFling函数不被触发,这时需要把onDown设置为true。
在用户滑动之前,需要注意:当用户将作出滑动手势时,需要停掉自动播放,然后用户结束滑动时,继续自动播放。
然后是重点,要实现带索引的效果,首先需要得到ViewFlipper的当前展示的View的索引值,而这个View当自动播放时是实时变化的,但是ViewFlipper并没有提供一个接口,在可以监听自动播放时view的变化。所以,需要自定义一个回调接口,监听displayView的变化,并把相应的索引值传递出去。这样才可以实现索引效果。
自定义的ViewFlipper源码如下:
package com.mobsut.mm.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.animation.AnimationUtils;
import android.widget.ViewFlipper;
/*
* 自定义的ViewFliper,监听滑动手势,以及自动指引
* @author jiakang
*/
import com.mobsut.mm.R;
public class GestureViewFliper extends ViewFlipper implements OnGestureListener {
GestureDetector gestureDetector = null;
private Context mContext = null;
FlipperFacousChangedListener flipperFacousChangedListener=null;
public GestureViewFliper(Context mContext) {
super(mContext);
}
public GestureViewFliper(Context mContext, AttributeSet attrs) {
super(mContext, attrs);
this.mContext = mContext;
gestureDetector = new GestureDetector(mContext, this);
setLongClickable(true);
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
return gestureDetector.onTouchEvent(event);
}
});
}
@Override
public void startFlipping() {
// TODO Auto-generated method stub
super.startFlipping();
setInAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_in));
setOutAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_out));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
stopFlipping(); //用户点击屏幕时,停止滑动
setAutoStart(false); //取消自动滑动
return this.gestureDetector.onTouchEvent(event); //把touch事件交给gesture处理
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return true; // 缺省值是false,在onTouchEvent后触发,如果为false,onFling将得不到down的事件即不触发
}
/*
* 重写了onFling,为了判断手势,让手势滑动
*
* @see android.view.GestureDetector.OnGestureListener#onFling(android.view.
* MotionEvent, android.view.MotionEvent, float, float)
*/
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
// TODO Auto-generated method stub
if (e2.getX() - e1.getX() > 120) { // 从左侧滑进
setInAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_in)); //设置进出动画
setOutAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_out));
//用户手势滑动结束,再次开始自动播放
showPrevious();
setAutoStart(true);
startFlipping();
return true;
} else if (e2.getX() - e1.getX() < -120) { //从右侧画出
setOutAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_out)); //设置进出动画
setInAnimation(AnimationUtils.loadAnimation(mContext,
R.anim.m_push_up_in));
//滑动结束,再次自动播放
showNext();
setAutoStart(true);
startFlipping();
return true;
}
return false;
}
@Override
public void showNext() {
// TODO Auto-generated method stub
super.showNext();
//监听向下向下翻页
flipperFacousChangedListener.onFliperChanged(getDisplayedChild());
}
@Override
public void showPrevious() {
// TODO Auto-generated method stub
super.showPrevious();
//监听向上翻页
flipperFacousChangedListener.onFliperChanged(getDisplayedChild());
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// TODO Auto-generated method stub
return true;
}
@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
/*
* 回调接口,用于监听viewflipper切花事件
*/
public interface FlipperFacousChangedListener{
public void onFliperChanged(int index);
}
public void setOnFacousChangedListener(FlipperFacousChangedListener flipperFacousChangedListener){
this.flipperFacousChangedListener=flipperFacousChangedListener;
}
}
接着是实现部分,指引条是由两张图片构成,选中项目一个颜色,未选中时一个颜色。实现比较简单,部分代码如下:
package com.mobsut.mm.foods;
public class FoodRecomFragment extends Fragment {
private Context mContext=null;
private LinearLayout mainLayout=null;
private LinearLayout indicatorLayout=null;
private ImageView[] mImageView;
private int[] fliperImage={R.drawable.fliper1,R.drawable.fliper2,R.drawable.fliper3};
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mContext=getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
mainLayout=(LinearLayout)inflater.inflate(R.layout.food_recom_fragment_main,container,false);
indicatorLayout=(LinearLayout)mainLayout.findViewById(R.id.food_recom_page_indicator);
GestureViewFliper viewFilper=(GestureViewFliper)mainLayout.findViewById(R.id.food_recom_viewfliper);
mImageView=new ImageView[fliperImage.length];
for(int i=0;i<fliperImage.length;i++){
ImageView iv=new ImageView(mContext);
ImageView indicatorView=new ImageView(mContext);
if(i==0){
indicatorView.setImageResource(R.drawable.page_selected);//初始默认选中第一张为当前指引
}else{
indicatorView.setImageResource(R.drawable.page_normal);
}
iv.setImageResource(fliperImage[i]);
//把指引条的图片添加到LinearLayout里面
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(6, 0, 0, 0);
indicatorView.setLayoutParams(lp);
iv.setScaleType(ScaleType.FIT_XY);
viewFilper.addView(iv, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
mImageView[i]=indicatorView;
indicatorLayout.addView(mImageView[i]);
}
viewFilper.setAutoStart(true); //让viewFlipper自动播放
viewFilper.setFlipInterval(4000); //间隔为4S
if(viewFilper.isAutoStart()&&viewFilper.isFlipping()){
viewFilper.startFlipping();
}
if(viewFilper.getDisplayedChild()!=0){
viewFilper.setInAnimation(AnimationUtils.loadAnimation(
mContext, R.anim.m_push_up_in)); //进出动画
viewFilper.setOutAnimation(AnimationUtils.loadAnimation(
mContext, R.anim.m_push_up_out));
}
viewFilper.setOnFacousChangedListener(new FlipperFacousChangedListener() {
@Override //实现监听接口
public void onFliperChanged(int index) {
// TODO Auto-generated method stub
for(int i=0;i<mImageView.length;i++){
if(i==index){
mImageView[i].setImageResource(R.drawable.page_selected);
}else{
mImageView[i].setImageResource(R.drawable.page_normal);
}
}
}
});
return mainLayout;
}
}