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




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

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

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

第一种:ViewFlipper+GestureDetector

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

[java] view plaincopy

    <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

[java] view plaincopy

    <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
    <set xmlns:android="http://schemas.android.com/apk/res/android"  
        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

[java] view plaincopy

    <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
    <set xmlns:android="http://schemas.android.com/apk/res/android" >  
      
        <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

[java] view plaincopy

    <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
    <set xmlns:android="http://schemas.android.com/apk/res/android"  
        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

[java] view plaincopy

    <span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  
    <set xmlns:android="http://schemas.android.com/apk/res/android" >  
      
        <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了.

下面重点是如何实现.

代码:

[java] view plaincopy

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

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

效果:

    

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

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

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

方法很简单,自定义一个listview.重写其onTouchEvent事件.
[java] view plaincopy

    @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,对其拦截事件进行处理.另外我们要用手势,判断上下左右滑动.

[java] view plaincopy

    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上下也可以滑动.
由于自己对事件分发不是很了解,所以不过多介绍,想知道的话,自己慢慢研究吧,我这里只是提供一个解决方法,我也在学习中...

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


       

          滑动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 plaincopy

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

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


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

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

在此 thanks for you .


源码一


源码二
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值