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

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

    

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

第一种:ViewFlipper+GestureDetector

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

 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

 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

 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

 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

 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了.

下面重点是如何实现.

代码:

  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         }, 5000, 5000);
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, 0, 0, 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>

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

效果:

    

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

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

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

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

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        Log.e("jj", "onTouchEvent...");
        int x = (int) ev.getX();
        int y = (int) ev.getY();
        int position = pointToPosition(x, y);
        // 只有headview才进行手势操作.
        if (position == 0) {
            // 注入手势
            gestureDetector.onTouchEvent(ev);
        }
        return super.onTouchEvent(ev);
    }

大家一看就明白了,我们只对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,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.

 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上下也可以滑动.

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

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

       

          滑动ing                                         滑动ing                                                 点击

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

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

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

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

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

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

 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滑动的冲突.

源码一

源码二


原文地址:https://www.cnblogs.com/liangstudyhome/p/3987172.html