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

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

1352275904_8547.jpg

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

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

第一种:ViewFlipper+GestureDetector

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


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<span style= "font-size:12px;" ><?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
     android:layout_width= "match_parent"
     android:layout_height= "match_parent"
     android:orientation= "vertical" >
 
     <FrameLayout
         android:id= "@+id/fl_main"
         android:layout_width= "match_parent"
         android:layout_height= "wrap_content" >
 
         <ViewFlipper
             android:id= "@+id/ViewFlipper01"
             android:layout_width= "fill_parent"
             android:layout_height= "fill_parent" >
         </ViewFlipper>
 
         <LinearLayout
             android:id= "@+id/ll_point"
             android:layout_width= "wrap_content"
             android:layout_height= "wrap_content"
             android:layout_gravity= "bottom|center_horizontal"
             android:layout_marginBottom= "10dp"
             android:src= "@drawable/indicator" />
     </FrameLayout>
 
</LinearLayout></span>

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

接下来我们看动画布局.

push_left_in.xml


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<span style= "font-size:12px;" ><?xml version= "1.0" encoding= "utf-8" ?>
     android:fillAfter= "true" >
 
     <translate
         android:duration= "500"
         android:fromXDelta= "-100%p"
         android:toXDelta= "0" />
 
     <alpha
         android:duration= "500"
         android:fromAlpha= "0.1"
         android:toAlpha= "1.0" />
 
</set></span>

push_left_out.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
<span style= "font-size:12px;" ><?xml version= "1.0" encoding= "utf-8" ?>
 
     <translate
         android:duration= "500"
         android:fromXDelta= "0"
         android:toXDelta= "-100%p" />
 
     <alpha
         android:duration= "500"
         android:fromAlpha= "1.0"
         android:toAlpha= "0.5" />
 
</set></span>

push_right_in.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<span style= "font-size:12px;" ><?xml version= "1.0" encoding= "utf-8" ?>
     android:fillAfter= "true" >
 
     <translate
         android:duration= "500"
         android:fromXDelta= "100%p"
         android:toXDelta= "0" />
 
     <alpha
         android:duration= "500"
         android:fromAlpha= "0.1"
         android:toAlpha= "1.0" />
 
</set></span>

push_right_out.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
<span style= "font-size:12px;" ><?xml version= "1.0" encoding= "utf-8" ?>
 
     <translate
         android:duration= "500"
         android:fromXDelta= "0"
         android:toXDelta= "100%p" />
 
     <alpha
         android:duration= "500"
         android:fromAlpha= "1.0"
         android:toAlpha= "0.5" />
 
</set></span>

我简单介绍下这些布局:

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

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

下面重点是如何实现.

代码:


001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
<span style= "font-size:12px;" > package com.jj.chage2;
 
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
 
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnTouchListener;
import android.view.animation.AnimationUtils;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
 
public class MainActivity extends Activity implements
         GestureDetector.OnGestureListener {
     private GestureDetector detector;
     private ViewFlipper flipper;
     private int image_id[] = { R.drawable.a, R.drawable.b, R.drawable.c };
     private ListView lv_main;
     private LayoutInflater layoutInflater;
     private LinearLayout ll_point;
     private FrameLayout frameLayout;
     private final String msg[] = { "one" , "two" , "three" , "four" , "five" ,
             "six" , "seven" };
     private int frameheight; // 图片的高度
     private int window_width; // 屏幕宽度
     private ArrayList<ImageView> imageViews; // ponit 集合
     private ArrayList<View> views; // flipper的孩子
     private Timer timer;
 
     /***
      * 初始化 point
      */
     void initPoint() {
         imageViews = new ArrayList<ImageView>();
         ImageView imageView;
         for ( int i = 0 ; i < image_id.length; i++) {
             imageView = new ImageView( this );
             imageView.setBackgroundResource(R.drawable.indicator);
             LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                     new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT,
                             LayoutParams.WRAP_CONTENT));
             layoutParams.leftMargin = 10 ;
             layoutParams.rightMargin = 10 ;
             ll_point.addView(imageView, layoutParams);
             imageViews.add(imageView);
         }
 
     }
 
     /***
      * ChildView
      */
     void initChildView(ViewFlipper flipper) {
         views = new ArrayList<View>();
         LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
                 LayoutParams.FILL_PARENT);
         for ( int i = 0 ; i < image_id.length; i++) {
             ImageView imageView = new ImageView( this );
             imageView.setScaleType(ScaleType.FIT_XY);
             Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
                     image_id[i]);
             Bitmap bitmap2 = getBitmap(bitmap, window_width);
             frameheight = bitmap2.getHeight(); // 获取要显示的高度
             imageView.setImageResource(image_id[i]);
             flipper.addView(imageView, layoutParams);
             views.add(imageView);
         }
         initPoint();
     }
 
     /***
      * 初始化 HeadImage
      */
     void initHeadImage() {
         layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         View headview = layoutInflater.inflate(R.layout.head_image, null );
 
         flipper = (ViewFlipper) headview.findViewById(R.id.ViewFlipper01);
 
         ll_point = (LinearLayout) headview.findViewById(R.id.ll_point);
         frameLayout = (FrameLayout) headview.findViewById(R.id.fl_main);
         initChildView(flipper);
 
         LayoutParams layoutParams = (LayoutParams) frameLayout
                 .getLayoutParams();
         layoutParams.height = frameheight;
         frameLayout.setLayoutParams(layoutParams);
         draw_Point( 0 ); // 默认首次进入
         lv_main.addHeaderView(headview); // 要卸载setAdapter前面
         lv_main.setAdapter( new ArrayAdapter<String>( this ,
                 android.R.layout.simple_list_item_1, msg));
 
     }
 
     /***
      * init view
      */
     void initView() {
         setTitle( "jjhappyforever..." );
         setContentView(R.layout.main);
         lv_main = (ListView) findViewById(R.id.lv_main);
         lv_main.setOnItemClickListener( new OnItemClickListener() {
 
             @Override
             public void onItemClick(AdapterView<?> parent, View view,
                     int position, long id) {
 
                 if (position != 0 )
                     Toast.makeText(MainActivity. this , msg[position - 1 ], 1 )
                             .show();
                 else {
                     int index = getPageIndex(flipper.getCurrentView());
                     Toast.makeText(MainActivity. this , "图" + index, 1 ).show();
 
                 }
 
             }
         });
         initHeadImage();
     }
 
     /***
      * 更新选中点
      *
      * @param index
      */
     private void draw_Point( int index) {
         for ( int i = 0 ; i < imageViews.size(); i++) {
             imageViews.get(i).setImageResource(R.drawable.indicator);
         }
         imageViews.get(index).setImageResource(R.drawable.indicator_focused);
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
         // 获取屏幕的宽度
         window_width = ( int ) getResources().getDimension(R.dimen.window_width);
         detector = new GestureDetector( this );
         initView();
 
         timer = new Timer( true );
         timer.schedule( new TimerTask() {
             @Override
             public void run() {
                 runOnUiThread( new Runnable() {
                     @Override
                     public void run() {
 
                         int pageIndex = getPageIndex(flipper.getCurrentView());
 
                         if (pageIndex == flipper.getChildCount() - 1 )
                             pageIndex = 0 ;
                         else
                             pageIndex++;
 
                         flipper.setInAnimation(AnimationUtils.loadAnimation(
                                 MainActivity. this , R.anim.push_right_in));
                         flipper.setOutAnimation(AnimationUtils.loadAnimation(
                                 MainActivity. this , R.anim.push_left_out));
                         flipper.showNext();
                         draw_Point(pageIndex);
 
                     }
                 });
             }
         }, 5000 , 5000 );
 
     }
 
     /***
      * 对图片处理
      *
      * @author zhangjia
      *
      */
     Bitmap getBitmap(Bitmap bitmap, int width) {
         int w = bitmap.getWidth();
         int h = bitmap.getHeight();
         Matrix matrix = new Matrix();
         float scale = ( float ) width / w;
         // 保证图片不变形.
         matrix.postScale(scale, scale);
         // w,h是原图的属性.
         return Bitmap.createBitmap(bitmap, 0 , 0 , w, h, matrix, true );
     }
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         this .detector.onTouchEvent(ev);
         return super .dispatchTouchEvent(ev);
     }
 
     @Override
     public boolean onDown(MotionEvent e) {
         return true ;
     }
 
     /***
      * 返回当前第几屏
      */
     int getPageIndex(View view) {
         for ( int i = 0 ; i < views.size(); i++) {
             if (view == views.get(i))
                 return i;
         }
         return 0 ;
 
     }
 
     /**
      * 监听滑动
      */
     @Override
     public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
             float velocityY) {
         int pageIndex = getPageIndex(flipper.getCurrentView());
 
         // 左划
         if (e1.getX() - e2.getX() > 120 ) {
             this .flipper.setInAnimation(AnimationUtils.loadAnimation( this ,
                     R.anim.push_right_in));
             this .flipper.setOutAnimation(AnimationUtils.loadAnimation( this ,
                     R.anim.push_left_out));
             this .flipper.showNext();
             if (pageIndex == flipper.getChildCount() - 1 )
                 draw_Point( 0 );
             else
                 draw_Point(++pageIndex);
             return true ;
             // 右划
         } else if (e1.getX() - e2.getX() < - 120 ) {
             this .flipper.setInAnimation(AnimationUtils.loadAnimation( this ,
                     R.anim.push_left_in));
             this .flipper.setOutAnimation(AnimationUtils.loadAnimation( this ,
                     R.anim.push_right_out));
             this .flipper.showPrevious();
             if (pageIndex == 0 )
                 draw_Point(flipper.getChildCount() - 1 );
             else
                 draw_Point(--pageIndex);
             return true ;
         }
         return true ;
     }
 
     @Override
     public void onLongPress(MotionEvent e) {
 
     }
 
     @Override
     public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
             float distanceY) {
         return false ;
     }
 
     @Override
     public void onShowPress(MotionEvent e) {
 
     }
 
     @Override
     public boolean onSingleTapUp(MotionEvent e) {
         return false ;
     }
 
}</span>

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

效果:

1352275969_2048.jpg

  1352276003_7017.jpg  1352276021_1735.jpg

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

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

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

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


01
02
03
04
05
06
07
08
09
10
11
12
13
@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,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.


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

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

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

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


1352362211_3687.jpg

   1352362247_1788.jpg    1352362692_4850.jpg

          滑动ing                                         滑动ing                                                 点击

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


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

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

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

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

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


01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
/***
      *
      * @author zhangjia
      *
      */
     class YScrollDetector extends SimpleOnGestureListener {
         @Override
         public boolean onScroll(MotionEvent e1, MotionEvent e2,
                 float distanceX, float distanceY) {
             if (Math.abs(distanceY) >= Math.abs(distanceX)) {
                 Log.e( "jj" , "上下...." );
                 return true ;
             }
             Log.e( "jj" , "左右...." );
             return false ;
         }

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值