前几天看到淘宝和易迅的客户端的广告栏做的不错,今天就尝试了一下,模仿着写了带指引的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
- <span style="color:#ff0000;">return true;</span> // 缺省值是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();
- //监听向下向下翻页
- <span style="color:#ff0000;">flipperFacousChangedListener.onFliperChanged(getDisplayedChild());</span>
- }
- @Override
- public void showPrevious() {
- // TODO Auto-generated method stub
- super.showPrevious();
- //监听向上翻页
- <span style="color:#ff0000;">flipperFacousChangedListener.onFliperChanged(getDisplayedChild());</span>
- }
- @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;
- }
- }