[置顶] Android高手进阶篇3-自定义ListView实现底部View自动隐藏和消失的功能

  以后每一周会分享Android技术难点,今天主要分享这样一个功能:有这样一个ListView,要求在屏幕底部有一个筛选排序的浮动框:

1、手指下拉隐藏,上滑显示 ;

2、如果没做任何操作,2S之后,要自动显示;

3、滑动到最底部,始终显示。

首先看其效果图:

[置顶] Android高手进阶篇3-自定义ListView实现底部View自动隐藏和消失的功能_第1张图片

 

实现上述效果,其实现原理如下:

 1、在屏幕顶部固定一个BottomView,XML布局最好使用RelativeLayout(底部的BottomView并不是 ListView的footView,这个是和footView独立的,想想为什么?)

 2、然后自定义ListView控件,监听onTouchEvent事件,主要是监听手指下滑和上滑事件,同时实现onScrollListener,监听是否滑动到最底部和最顶部

3、 ListView监听事件中,控制bottomView的显示和隐藏,所以ListView提供一个接口,设置底部bootomView的内容,然后获之后,就可以对bottomView进行控制,同时加上动画效果。

接下来看是如何的具体实现这种效果:

1。底部BottomView的内容如下,这个XML文件的内容是自定义的,根据各项目的内容需求来定义的,我例子中bottom_view.xml:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/button_layout"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:background="#cbcbcb"
    android:gravity="center_vertical"
    android:orientation="horizontal" >

        <Button android:layout_height="40dp"
                  android:layout_width="wrap_content"
                  android:layout_weight="1"
                  android:text="价格"  />

    <Button android:layout_height="40dp"
              android:layout_width="wrap_content"
              android:layout_weight="1"
              android:text="好评"  />

    <Button android:layout_height="40dp"
            android:layout_width="wrap_content"
            android:layout_weight="1"
            android:text="筛选"  />


</LinearLayout>


2、main.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
        >

    <com.example.BottomFloatListView.BottomFloatListView
            android:id="@+id/listView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:fadingEdge="none"
            />


    <include
            android:id="@+id/bottombar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            layout="@layout/bottom_view"
            >
    </include>
</RelativeLayout>


main.xml中采用的RelativeLayout,有自定义的控件BottomFloatListView,然后屏幕底部放的是bottom_view,我是通过include的方式引用过来的,这样多处引用比较方便。

3、自定义ListView控件BottomFloatListView代码如下

package com.example.BottomFloatListView;

import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.OvershootInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.*;
import android.widget.AbsListView.OnScrollListener;



/**
 * 底部View自动隐藏和消失listview(其他ListView可以继承该类,如CtripBottomRefreshListView类等)
 * 
 * @author zhiwen.nan
 * @Date 2013-9-28 下午3:35:15
 * 
 */
public class BottomFloatListView extends ListView implements OnScrollListener {

    public View mBottomBar;
    private int mCurrentScrollState;
    private boolean bIsMoved = false;
    private boolean bIsDown = false;
    private int mDeltaY;
    private float mMotionY;
	private int oldFirstVisibleItem = 0;
    private Handler mHandler = new Handler();
    private static final String TAG = "BottomFloatListView";


	public BottomFloatListView(Context context) {
		this(context, null);
		super.setOnScrollListener(this);
	}

	public BottomFloatListView(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
		super.setOnScrollListener(this);
	}

	public BottomFloatListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		super.setOnScrollListener(this);
	}


	@Override
	public void setAdapter(ListAdapter adapter) {
		super.setAdapter(adapter);
	}


	@Override
	public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

        showBottomViewOnBottom(visibleItemCount, totalItemCount, firstVisibleItem);

	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {

        hideBottomViewOnScrollStateChanged(view, scrollState);

	}


    @Override
	public boolean onTouchEvent(MotionEvent ev) {
    	
    	 float y = ev.getY();
         float x = ev.getX();
         Log.d("FloatListView", "onTouchEvent" + "" + x + "" + y);
         int action = ev.getAction() & MotionEvent.ACTION_MASK;
         switch (action) {
             case MotionEvent.ACTION_DOWN:
                 action_down(y);
                 break;
             case MotionEvent.ACTION_MOVE:
                 mDeltaY = (int) (y - mMotionY);
                 bIsMoved = true;
                 //移动的时候,要移除掉显示bottomView的消息
                 mHandler.removeCallbacks(showBottomBarRunnable);
                 //补齐action_down事件,因为有的时候,action_down 事件没有执行
                 action_down(y);
                 break;
             case MotionEvent.ACTION_UP:
                 bIsMoved = false;
                 bIsDown = false;
                 if (!bIsMoved && !bIsDown) {
                     // 如果屏幕上什么没做,则过2s之后要显示bottomView
                     mHandler.postDelayed(showBottomBarRunnable, 2000);
                 }
                 if (mDeltaY < 0) { //下滑影藏
                 	 hideBottomBar();
                 } else {  //上滑显示
                     showBottomBar();
                 }

                 bIsMoved = false;
                 break;

         }

		return super.onTouchEvent(ev);
	}
    
    
    private void action_down(float y){
    	  mMotionY = y;
          bIsDown = true;
          Log.d(TAG, "action down execed");
          mHandler.removeCallbacks(showBottomBarRunnable);
    }


    /**
     * 滑动到顶部时,要隐藏bottomView
     * @param view
     * @param scrollState
     */
    private void hideBottomViewOnScrollStateChanged(AbsListView view, int scrollState) {
        mCurrentScrollState = scrollState;
        if(view!=null){
        	 if (view.getFirstVisiblePosition() == 0 && scrollState == SCROLL_STATE_IDLE) {
                 hideBottomBar();
                 Log.d(TAG, "hide bottom view");
             }
        }
       

    }

    /**
     * 显示底部浮动栏
     */
    public void showBottomBar() {

        if (mBottomBar != null && mBottomBar.getVisibility() == View.GONE) {
            mBottomBar.setVisibility(View.INVISIBLE);
            Animation translateAnimation = new TranslateAnimation(mBottomBar.getLeft(), mBottomBar.getLeft(),30, 0);
            translateAnimation.setDuration(300);
            translateAnimation.setInterpolator(new OvershootInterpolator(0.6f));
            mBottomBar.startAnimation(translateAnimation);
            translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mBottomBar.setVisibility(View.VISIBLE);
                }
            });
        }
    }

    /**
     * 隐藏浮动底部栏
     */
    private void hideBottomBar() {

        
        if (mBottomBar != null && mBottomBar.getVisibility() == View.VISIBLE) {
            Animation translateAnimation = new TranslateAnimation(mBottomBar.getLeft(), mBottomBar.getLeft(), 0, 30);
            translateAnimation.setDuration(300);
            translateAnimation.setInterpolator(new OvershootInterpolator(0.6f));
            mBottomBar.startAnimation(translateAnimation);
            translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    mBottomBar.setVisibility(View.GONE);
                }
            });
        }
    }

    /**
     * 滑动到底部时直接显示bottomView
     * @param visibleItemCount
     * @param totalItemCount
     * @param firstVisibleItem
     */
    private void showBottomViewOnBottom(int visibleItemCount, int totalItemCount, int firstVisibleItem) {
        
        	Log.d(TAG, "visible bottem item count:"  + "firstVisibleItem:" +  firstVisibleItem + "oldFirstVisibleItem:" + oldFirstVisibleItem + mBottomBar);
             if(getLastVisiblePosition() ==   totalItemCount -1 && mCurrentScrollState != SCROLL_STATE_IDLE){
                 showBottomBar();
             }
    }

    private Runnable showBottomBarRunnable = new Runnable() {

        @Override
        public void run() {
            showBottomBar();
        }

    };


    /**
	 * 将需要隐藏显示的view传入
	 * 
	 * @param bottomBar
	 */
	public void setBottomBar(ViewGroup bottomBar) {
		this.mBottomBar = bottomBar;
	}

}




上述代码中,重要和难理解的地方,都加了注释,很好理解。




4、主界面测试的Activity,MainActivity代码如下

 

package com.example.BottomFloatListView;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {
    private  BottomFloatListView mBottomFloatListView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mBottomFloatListView = (BottomFloatListView)findViewById(R.id.listView)  ;
        mBottomFloatListView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));
        ViewGroup bottomView = (ViewGroup)findViewById(R.id.bottombar) ;
        mBottomFloatListView.setBottomBar(bottomView);
    }

    private List<String> getData(){

        List<String> data = new ArrayList<String>();

        for(int i = 0; i <100; i++)      {
            data.add("测试数据" + i);
        }

        return data;

    }
}


上述Activity中告诉了如何使用了BottomFloatListView控件,下面两句代码比较关键:

ViewGroup bottomView = (ViewGroup)findViewById(R.id.bottombar) ;
        mBottomFloatListView.setBottomBar(bottomView);


 

将底部的bottomView传入到ListView中,就可以让ListView具有底部View自动隐藏和消失的功能。

 集成到自己项目中,仅需1分钟搞定,有木有,如果有什么疑问,欢迎留言提问   。

 

源代码下载:

http://download.csdn.net/detail/nanzhiwen666/6392729


 

你可能感兴趣的:([置顶] Android高手进阶篇3-自定义ListView实现底部View自动隐藏和消失的功能)