android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)

http://blog.csdn.net/jj120522/article/details/8158399

首先我们还是看一些示例:(网易,新浪,百度)

android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)  android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)  android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)
显示效果都不错,可是手感就不一样了,百度最棒,网易还行,新浪就操作很不好,这里我说的是滑动切换图片.自己可以测试一下.不得不说牛叉的公司确实有哦牛叉的道理.

下面我简单的介绍下实现方法:其实就是listview addHeaderView.只不过这个view是一个可以切换图片的view,至于这个view怎么做,就要根据自己的喜爱了,实现有多种方法,下面我简单介绍一下.

第一种:ViewFlipper+GestureDetector

主布局就是一个listview,这里就不介绍了,我介绍下切换图片布局head_iamge.xml

 

[java] view plain copy
  1. <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <FrameLayout  
  8.         android:id="@+id/fl_main"  
  9.         android:layout_width="match_parent"  
  10.         android:layout_height="wrap_content" >  
  11.   
  12.         <ViewFlipper  
  13.             android:id="@+id/ViewFlipper01"  
  14.             android:layout_width="fill_parent"  
  15.             android:layout_height="fill_parent" >  
  16.         </ViewFlipper>  
  17.   
  18.         <LinearLayout  
  19.             android:id="@+id/ll_point"  
  20.             android:layout_width="wrap_content"  
  21.             android:layout_height="wrap_content"  
  22.             android:layout_gravity="bottom|center_horizontal"  
  23.             android:layout_marginBottom="10dp"  
  24.             android:src="@drawable/indicator" />  
  25.     </FrameLayout>  
  26.   
  27. </LinearLayout></span>  

这里我就添加一系列切换点,至于显示新闻标题,透明效果等等,大家可以自己布局,方法同理,不难实现.

接下来我们看动画布局.

push_left_in.xml

 

[java] view plain copy
  1. <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:fillAfter="true" >  
  4.   
  5.     <translate  
  6.         android:duration="500"  
  7.         android:fromXDelta="-100%p"  
  8.         android:toXDelta="0" />  
  9.   
  10.     <alpha  
  11.         android:duration="500"  
  12.         android:fromAlpha="0.1"  
  13.         android:toAlpha="1.0" />  
  14.   
  15. </set></span>  

push_left_out.xml

 

[java] view plain copy
  1. <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   
  4.     <translate  
  5.         android:duration="500"  
  6.         android:fromXDelta="0"  
  7.         android:toXDelta="-100%p" />  
  8.   
  9.     <alpha  
  10.         android:duration="500"  
  11.         android:fromAlpha="1.0"  
  12.         android:toAlpha="0.5" />  
  13.   
  14. </set></span>  

push_right_in.xml

 

[java] view plain copy
  1. <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:fillAfter="true" >  
  4.   
  5.     <translate  
  6.         android:duration="500"  
  7.         android:fromXDelta="100%p"  
  8.         android:toXDelta="0" />  
  9.   
  10.     <alpha  
  11.         android:duration="500"  
  12.         android:fromAlpha="0.1"  
  13.         android:toAlpha="1.0" />  
  14.   
  15. </set></span>  

push_right_out.xml

 

[java] view plain copy
  1. <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android" >  
  3.   
  4.     <translate  
  5.         android:duration="500"  
  6.         android:fromXDelta="0"  
  7.         android:toXDelta="100%p" />  
  8.   
  9.     <alpha  
  10.         android:duration="500"  
  11.         android:fromAlpha="1.0"  
  12.         android:toAlpha="0.5" />  
  13.   
  14. </set></span>  

我简单介绍下这些布局:

push_left_in:左边进入,则要进入的view初始位置在-100%p位置,终止位置在0,而push_left_out:左边出来,则此时view的位置在0,而终止位置在-100%p.

右进右出同理,至于alpha渐变,很简单,动画就说道这里,相信了解动画的同学们不用看就ok了.

下面重点是如何实现.

代码:

 

[java] view plain copy
  1. <span style="font-size:12px;">package com.jj.chage2;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6.   
  7. import android.app.Activity;  
  8. import android.content.Context;  
  9. import android.graphics.Bitmap;  
  10. import android.graphics.BitmapFactory;  
  11. import android.graphics.Matrix;  
  12. import android.os.Bundle;  
  13. import android.util.Log;  
  14. import android.view.GestureDetector;  
  15. import android.view.LayoutInflater;  
  16. import android.view.MotionEvent;  
  17. import android.view.View;  
  18. import android.view.ViewGroup;  
  19. import android.view.View.OnTouchListener;  
  20. import android.view.animation.AnimationUtils;  
  21. import android.widget.AdapterView;  
  22. import android.widget.AdapterView.OnItemClickListener;  
  23. import android.widget.Button;  
  24. import android.widget.ImageView.ScaleType;  
  25. import android.widget.LinearLayout.LayoutParams;  
  26. import android.widget.ArrayAdapter;  
  27. import android.widget.FrameLayout;  
  28. import android.widget.ImageView;  
  29. import android.widget.LinearLayout;  
  30. import android.widget.ListView;  
  31. import android.widget.TextView;  
  32. import android.widget.Toast;  
  33. import android.widget.ViewFlipper;  
  34.   
  35. public class MainActivity extends Activity implements  
  36.         GestureDetector.OnGestureListener {  
  37.     private GestureDetector detector;  
  38.     private ViewFlipper flipper;  
  39.     private int image_id[] = { R.drawable.a, R.drawable.b, R.drawable.c };  
  40.     private ListView lv_main;  
  41.     private LayoutInflater layoutInflater;  
  42.     private LinearLayout ll_point;  
  43.     private FrameLayout frameLayout;  
  44.     private final String msg[] = { "one""two""three""four""five",  
  45.             "six""seven" };  
  46.     private int frameheight;// 图片的高度  
  47.     private int window_width;// 屏幕宽度  
  48.     private ArrayList<ImageView> imageViews;// ponit 集合  
  49.     private ArrayList<View> views;// flipper的孩子  
  50.     private Timer timer;  
  51.   
  52.     /*** 
  53.      * 初始化 point 
  54.      */  
  55.     void initPoint() {  
  56.         imageViews = new ArrayList<ImageView>();  
  57.         ImageView imageView;  
  58.         for (int i = 0; i < image_id.length; i++) {  
  59.             imageView = new ImageView(this);  
  60.             imageView.setBackgroundResource(R.drawable.indicator);  
  61.             LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(  
  62.                     new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,  
  63.                             LayoutParams.WRAP_CONTENT));  
  64.             layoutParams.leftMargin = 10;  
  65.             layoutParams.rightMargin = 10;  
  66.             ll_point.addView(imageView, layoutParams);  
  67.             imageViews.add(imageView);  
  68.         }  
  69.   
  70.     }  
  71.   
  72.     /*** 
  73.      * ChildView 
  74.      */  
  75.     void initChildView(ViewFlipper flipper) {  
  76.         views = new ArrayList<View>();  
  77.         LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,  
  78.                 LayoutParams.FILL_PARENT);  
  79.         for (int i = 0; i < image_id.length; i++) {  
  80.             ImageView imageView = new ImageView(this);  
  81.             imageView.setScaleType(ScaleType.FIT_XY);  
  82.             Bitmap bitmap = BitmapFactory.decodeResource(getResources(),  
  83.                     image_id[i]);  
  84.             Bitmap bitmap2 = getBitmap(bitmap, window_width);  
  85.             frameheight = bitmap2.getHeight();// 获取要显示的高度  
  86.             imageView.setImageResource(image_id[i]);  
  87.             flipper.addView(imageView, layoutParams);  
  88.             views.add(imageView);  
  89.         }  
  90.         initPoint();  
  91.     }  
  92.   
  93.     /*** 
  94.      * 初始化 HeadImage 
  95.      */  
  96.     void initHeadImage() {  
  97.         layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  98.         View headview = layoutInflater.inflate(R.layout.head_image, null);  
  99.   
  100.         flipper = (ViewFlipper) headview.findViewById(R.id.ViewFlipper01);  
  101.   
  102.         ll_point = (LinearLayout) headview.findViewById(R.id.ll_point);  
  103.         frameLayout = (FrameLayout) headview.findViewById(R.id.fl_main);  
  104.         initChildView(flipper);  
  105.   
  106.         LayoutParams layoutParams = (LayoutParams) frameLayout  
  107.                 .getLayoutParams();  
  108.         layoutParams.height = frameheight;  
  109.         frameLayout.setLayoutParams(layoutParams);  
  110.         draw_Point(0);// 默认首次进入  
  111.         lv_main.addHeaderView(headview);// 要卸载setAdapter前面  
  112.         lv_main.setAdapter(new ArrayAdapter<String>(this,  
  113.                 android.R.layout.simple_list_item_1, msg));  
  114.   
  115.     }  
  116.   
  117.     /*** 
  118.      * init view 
  119.      */  
  120.     void initView() {  
  121.         setTitle("jjhappyforever...");  
  122.         setContentView(R.layout.main);  
  123.         lv_main = (ListView) findViewById(R.id.lv_main);  
  124.         lv_main.setOnItemClickListener(new OnItemClickListener() {  
  125.   
  126.             @Override  
  127.             public void onItemClick(AdapterView<?> parent, View view,  
  128.                     int position, long id) {  
  129.   
  130.                 if (position != 0)  
  131.                     Toast.makeText(MainActivity.this, msg[position - 1], 1)  
  132.                             .show();  
  133.                 else {  
  134.                     int index = getPageIndex(flipper.getCurrentView());  
  135.                     Toast.makeText(MainActivity.this"图" + index, 1).show();  
  136.   
  137.                 }  
  138.   
  139.             }  
  140.         });  
  141.         initHeadImage();  
  142.     }  
  143.   
  144.     /*** 
  145.      * 更新选中点 
  146.      *  
  147.      * @param index 
  148.      */  
  149.     private void draw_Point(int index) {  
  150.         for (int i = 0; i < imageViews.size(); i++) {  
  151.             imageViews.get(i).setImageResource(R.drawable.indicator);  
  152.         }  
  153.         imageViews.get(index).setImageResource(R.drawable.indicator_focused);  
  154.     }  
  155.   
  156.     @Override  
  157.     public void onCreate(Bundle savedInstanceState) {  
  158.         super.onCreate(savedInstanceState);  
  159.         setContentView(R.layout.main);  
  160.         // 获取屏幕的宽度  
  161.         window_width = (int) getResources().getDimension(R.dimen.window_width);  
  162.         detector = new GestureDetector(this);  
  163.         initView();  
  164.   
  165.         timer = new Timer(true);  
  166.         timer.schedule(new TimerTask() {  
  167.             @Override  
  168.             public void run() {  
  169.                 runOnUiThread(new Runnable() {  
  170.                     @Override  
  171.                     public void run() {  
  172.   
  173.                         int pageIndex = getPageIndex(flipper.getCurrentView());  
  174.   
  175.                         if (pageIndex == flipper.getChildCount() - 1)  
  176.                             pageIndex = 0;  
  177.                         else  
  178.                             pageIndex++;  
  179.   
  180.                         flipper.setInAnimation(AnimationUtils.loadAnimation(  
  181.                                 MainActivity.this, R.anim.push_right_in));  
  182.                         flipper.setOutAnimation(AnimationUtils.loadAnimation(  
  183.                                 MainActivity.this, R.anim.push_left_out));  
  184.                         flipper.showNext();  
  185.                         draw_Point(pageIndex);  
  186.   
  187.                     }  
  188.                 });  
  189.             }  
  190.         }, 50005000);  
  191.   
  192.     }  
  193.   
  194.     /*** 
  195.      * 对图片处理 
  196.      *  
  197.      * @author zhangjia 
  198.      *  
  199.      */  
  200.     Bitmap getBitmap(Bitmap bitmap, int width) {  
  201.         int w = bitmap.getWidth();  
  202.         int h = bitmap.getHeight();  
  203.         Matrix matrix = new Matrix();  
  204.         float scale = (float) width / w;  
  205.         // 保证图片不变形.  
  206.         matrix.postScale(scale, scale);  
  207.         // w,h是原图的属性.  
  208.         return Bitmap.createBitmap(bitmap, 00, w, h, matrix, true);  
  209.     }  
  210.   
  211.     @Override  
  212.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  213.         this.detector.onTouchEvent(ev);  
  214.         return super.dispatchTouchEvent(ev);  
  215.     }  
  216.   
  217.     @Override  
  218.     public boolean onDown(MotionEvent e) {  
  219.         return true;  
  220.     }  
  221.   
  222.     /*** 
  223.      * 返回当前第几屏 
  224.      */  
  225.     int getPageIndex(View view) {  
  226.         for (int i = 0; i < views.size(); i++) {  
  227.             if (view == views.get(i))  
  228.                 return i;  
  229.         }  
  230.         return 0;  
  231.   
  232.     }  
  233.   
  234.     /** 
  235.      * 监听滑动 
  236.      */  
  237.     @Override  
  238.     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  239.             float velocityY) {  
  240.         int pageIndex = getPageIndex(flipper.getCurrentView());  
  241.   
  242.         // 左划  
  243.         if (e1.getX() - e2.getX() > 120) {  
  244.             this.flipper.setInAnimation(AnimationUtils.loadAnimation(this,  
  245.                     R.anim.push_right_in));  
  246.             this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this,  
  247.                     R.anim.push_left_out));  
  248.             this.flipper.showNext();  
  249.             if (pageIndex == flipper.getChildCount() - 1)  
  250.                 draw_Point(0);  
  251.             else  
  252.                 draw_Point(++pageIndex);  
  253.             return true;  
  254.             // 右划  
  255.         } else if (e1.getX() - e2.getX() < -120) {  
  256.             this.flipper.setInAnimation(AnimationUtils.loadAnimation(this,  
  257.                     R.anim.push_left_in));  
  258.             this.flipper.setOutAnimation(AnimationUtils.loadAnimation(this,  
  259.                     R.anim.push_right_out));  
  260.             this.flipper.showPrevious();  
  261.             if (pageIndex == 0)  
  262.                 draw_Point(flipper.getChildCount() - 1);  
  263.             else  
  264.                 draw_Point(--pageIndex);  
  265.             return true;  
  266.         }  
  267.         return true;  
  268.     }  
  269.   
  270.     @Override  
  271.     public void onLongPress(MotionEvent e) {  
  272.   
  273.     }  
  274.   
  275.     @Override  
  276.     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,  
  277.             float distanceY) {  
  278.         return false;  
  279.     }  
  280.   
  281.     @Override  
  282.     public void onShowPress(MotionEvent e) {  
  283.   
  284.     }  
  285.   
  286.     @Override  
  287.     public boolean onSingleTapUp(MotionEvent e) {  
  288.         return false;  
  289.     }  
  290.   
  291. }</span>  

上诉代码写的有点小乱,别介意.

效果:

android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)  android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)  android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)

你可以手势左右滑动图片切换,由于我们加入了动画,则在切换图片效果会比较人性,这一 点比较不错.另外一点,我开启了timer,让它自己切换,感觉这点比较不错,可惜好多应用都没有这么搞,总之实现就行了,我们开发人员嘛,就是开发别人 想出来的东西,感慨程序员苦逼...

如果你按照上诉操作的话会有几个问题:1,我移动图片下面的item图片也会切换,2,我在滑动切换图片的时候偶尔也会执行onclick事件,这两点bug严重不允许,为之我也煞费神经细胞啊,没办法因为基础不好,对触摸种种事件还是搞不明白,有时间了还得在看看研究研究,扯远了,下面我说下解决方法:

第一:我只让listview的第一项监听手势操作,其他的不执行.

方法很简单,自定义一个listview.重写其onTouchEvent事件.

[java] view plain copy
  1. @Override  
  2.     public boolean onTouchEvent(MotionEvent ev) {  
  3.         Log.e("jj""onTouchEvent...");  
  4.         int x = (int) ev.getX();  
  5.         int y = (int) ev.getY();  
  6.         int position = pointToPosition(x, y);  
  7.         // 只有headview才进行手势操作.  
  8.         if (position == 0) {  
  9.             // 注入手势  
  10.             gestureDetector.onTouchEvent(ev);  
  11.         }  
  12.         return super.onTouchEvent(ev);  
  13.     }  


大家一看就明白了,我们只对position==0进行手势监听也 许有人问了,其实也可以直接在MainActivity中的dispatchTouchEvent分发事件中获取点击listview的 position,可是这样不准确,我点击第0项获取的有的是0,有的是1,原因目前不明,不过但可以肯定,这样是能获取listview的 position的,所以就干脆自定义吧,这样不会出错.这样解决了不会滑动下面item图片跟着切换.

再有就是我们要把listview item的第一项 onclick事件禁止了,我们直接把这个点击事件搬到onSingleTapUp中,这样就不会因为手势操作而影响item的onclick事件了,这 样问题基本都解决了,其实我想有简单的方法,只要把Touch事件弄懂,可惜啊...不给力啊...

效果和上面一样.

经过多次测试,目前没有发现问题,如有不妥我会给出提示.

 

第二种方法:ViewPager.

viewpager效果相比大家都熟知,因此我就省略显示的那部分,方法和上面一样,只是显示用的是viewpager而已.

但是这里面存在一个严重的问题:ViewPager和listview共存的问题,二者都有自身的滑动事件,必然要产生冲突。viewpager操作起来相当的不灵敏.

这里我重点说一下解决办法:我们需要自定义Listview,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.

 

[java] view plain copy
  1. package com.jj.chage;  
  2.   
  3. import android.content.Context;  
  4. import android.util.AttributeSet;  
  5. import android.util.Log;  
  6. import android.view.GestureDetector;  
  7. import android.view.GestureDetector.SimpleOnGestureListener;  
  8. import android.view.MotionEvent;  
  9. import android.view.View;  
  10. import android.widget.ListView;  
  11.   
  12. public class MyListView extends ListView {  
  13.     private GestureDetector mGestureDetector;  
  14.     View.OnTouchListener mGestureListener;  
  15.   
  16.     public MyListView(Context context) {  
  17.         super(context);  
  18.     }  
  19.   
  20.     public MyListView(Context context, AttributeSet attrs) {  
  21.         super(context, attrs);  
  22.         mGestureDetector = new GestureDetector(new YScrollDetector());  
  23.         setFadingEdgeLength(0);  
  24.     }  
  25.   
  26.     public MyListView(Context context, AttributeSet attrs, int defStyle) {  
  27.         super(context, attrs, defStyle);  
  28.     }  
  29.   
  30.     @Override  
  31.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  32.         super.onInterceptTouchEvent(ev);  
  33.         return mGestureDetector.onTouchEvent(ev);  
  34.     }  
  35.   
  36.     class YScrollDetector extends SimpleOnGestureListener {  
  37.         @Override  
  38.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  39.                 float distanceX, float distanceY) {  
  40.             if (Math.abs(distanceY) >= Math.abs(distanceX)) {  
  41.                 Log.e("jj""上下....");  
  42.                 return true;  
  43.             }  
  44.             Log.e("jj""左右....");  
  45.             return false;  
  46.         }  
  47.     }  
  48. }  

这样viewpager滑动就不会受listview干扰了,listview上下也可以滑动.

由于自己对事件分发不是很了解,所以不过多介绍,想知道的话,自己慢慢研究吧,我这里只是提供一个解决方法,我也在学习中...

其他部分不难,这里就不讲解了.


android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)   android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)    android listview的HeadView左右切换图片(仿新浪,网易,百度等切换图片)

          滑动ing                                         滑动ing                                                 点击

感觉还是第二种方法好,这也是为什么那么多客户端都是这么搞,不过各有千秋,因人而异.

 

对第二种方法实现简单讲解:

我们的目的是:我们左右滑动ViewPager的时候ListView不影响,而当ViewPager上下滑动的时候可以随意滑动.

我们可以这样做:我们把onInterceptTouchEvent返回值更改为fase,那么意味着,如果孩子存在onInterceptTouchEvent那么会继续传递给孩子的onInterceptTouchEvent...后面我们不管(此时ListView失去touch事件),这个时候ViewPager获取Touch事件. 这个时候ViewPager就可以左右滑动(不可以上下滑动)。 如果孩子不存在onInterceptTouchEvent,ListView执行本身ontouch.  

那么把onInterceptTouchEvent返回值更改为true.意思就是:我对touch事件进行拦截,不进行向下传递,直接执行自身的Ontouch事件,这个时候ViewPager就可以上下滑了(不可以左右滑动切换).

根据实情,那么我们如何动态控制这个onInterceptTouchEvent的返回值,这个时候我们可以借助:GestureDetector手势来实现.

 

[java] view plain copy
  1. /*** 
  2.      *  
  3.      * @author zhangjia 
  4.      *  
  5.      */  
  6.     class YScrollDetector extends SimpleOnGestureListener {  
  7.         @Override  
  8.         public boolean onScroll(MotionEvent e1, MotionEvent e2,  
  9.                 float distanceX, float distanceY) {  
  10.             if (Math.abs(distanceY) >= Math.abs(distanceX)) {  
  11.                 Log.e("jj""上下....");  
  12.                 return true;  
  13.             }  
  14.             Log.e("jj""左右....");  
  15.             return false;  
  16.         }  

上面这个方法可以根据手势来判断我们手的滑动方向.而:boolean b = mGestureDetector.onTouchEvent(ev);

这个值就是onScroll返回的值.这个值是代表我们手势mGestureDetector消费了没,为什么这么说呢,因为这个和我们外界的touch分开了,就算我们在这里消费了那么外面该怎么执行就怎么执行。经过测试觉得mGestureDetector.onTouchEvent(ev)这个方法就是执行手势相应方法,然后返回的是onScroll的返回值.

而当我们上下滑动的时候mGestureDetector.onTouchEvent(ev)返回true,而ViewPager需要上下滑动的时候只需要将onInterceptTouchEvent的返回值更改为true,左右滑动同理.

那么这样我们就实现了ViewPager与ListView滑动的冲突.

就说道这里,如有错误和疑问请留言.

 

我将源码上传网上,如有不懂自行下载,注释已很明确.

如有问题请留言,对你有帮助的话,记得赞一个哦.

在此 thanks for you .

 

源码一

 

源码二

 

 

你可能感兴趣的:(android,ListView)