zoukankan      html  css  js  c++  java
  • 【转】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滑动的冲突.

    源码一

    源码二


  • 相关阅读:
    C/C++预定义编译宏
    vi/vim教程
    Shell参数展开
    GNU构建系统和Autotool
    Makefile强制目标(没有命令或依赖的规则)
    C程序的存储空间布局(内存结构)
    linux deamon
    JavaScript高级程序设计——闭包
    PureMVC(JS版)源码解析(三):Observer类
    PureMVC(JS版)源码解析(二):Notification类
  • 原文地址:https://www.cnblogs.com/liangstudyhome/p/3987172.html
Copyright © 2011-2022 走看看