Custom Sliding Menu: 左右滑动的ListView

目标:制作现阶段App中常见的左右滑动ListView。

特点:有多种方法实现,一种是使用官方menudrawer;一种是开源的SlidingMenu;还有其他各种各样的方法。我在这里使用的是自定义方法(相对使用各种现成的控件,这种方法倒不是麻烦,不过就是要判断各种不同的情况,要没有什么bug需要花费不少心机;好处就是不用引入一大堆包,而且有一种尽在掌握的感觉,呵呵~~)


下面是一个从右边滑动出来的菜单例子,e.g.


SlidingViewGroup.java

package com.testApp5;

import android.app.Activity;
import android.content.Context;
import android.graphics.Point;
import android.os.Handler;
import android.os.Message;
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.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;

public class SlidingViewGroup extends ViewGroup {
	
	private final float WIDTH_RATE = 0.65f;
	private Main mainView;
	private Side sideView;
	private Point point;
	private boolean isSliding = false;
	private boolean isMoveOut = false;
	private int xSideLeft;
	private int sideWidth;
	private int xMoveSideLeft;
	private int xMoveStart;
	private int yMoveStart;
	private int yMoveSideTop;
	private int yMoveSideBottom;
	private Handler mHandler = new Handler() {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case 1:				// side出现
				moveIn();
				break;
			case 3:				// side收起来
				moveOut();
				break;
			case 5: 				// 拖动时
				moving();
				break;
			default:
				break;
			}
		}
	};
	
	public void init(Activity activity, Point point) {
		initParam(point);
		initView(activity);
	}
	public void initParam(Point point) {
		this.point = point;
		xSideLeft = (int) (point.x * (1 - WIDTH_RATE));
		sideWidth = (int) (point.x * WIDTH_RATE);
		xMoveSideLeft = xSideLeft;
	}
	public void initView(Activity activity) {
		mainView = new Main(this.getContext(), this);
		sideView = new Side(activity, this.getContext(), this);
		this.addView(mainView.getView());
		this.addView(sideView.getView());
		mainView.getView().setVisibility(View.VISIBLE);
		sideView.getView().setVisibility(View.GONE);
	}
	
	public void moveIn() {
		TranslateAnimation mShowAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 1.0f, 
				Animation.RELATIVE_TO_SELF, 0.0f,
				Animation.RELATIVE_TO_SELF, 0.0f, 
				Animation.RELATIVE_TO_SELF, 0.0f);
		mShowAnimation.setDuration(300);
		sideView.getView().setVisibility(View.VISIBLE);
		sideView.getView().startAnimation(mShowAnimation);
	}
	
	public void moveOut() {
		TranslateAnimation mHideAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, 
				Animation.RELATIVE_TO_SELF, 1.0f,
				Animation.RELATIVE_TO_SELF, 0.0f, 
				Animation.RELATIVE_TO_SELF, 0.0f);
		mHideAnimation.setDuration(300);
		sideView.getView().startAnimation(mHideAnimation);
		mHideAnimation.setAnimationListener(new AnimationListener() {
			@Override
			public void onAnimationStart(Animation animation) {
				// TODO Auto-generated method stub
			}
			@Override
			public void onAnimationRepeat(Animation animation) {
				// TODO Auto-generated method stub
			}
			@Override
			public void onAnimationEnd(Animation animation) {
				sideView.getView().setVisibility(View.GONE);
			}
		});
	}
	
	public void moving() {
		sideView.getView().layout(xMoveSideLeft, yMoveSideTop, (xMoveSideLeft + sideWidth), yMoveSideBottom);
	}
	
	public void moveHandler() {
		mHandler.postDelayed(new Runnable() {
			@Override
			public void run() {
				Message msg = new Message();
				if (View.VISIBLE == sideView.getView().getVisibility()) {
					if (isMoveOut) {
						// side收起来
						msg.what = 3;
						mHandler.sendMessage(msg);
						mHandler.removeCallbacks(this);
					} else if (isSliding) {
						// 拖动时
						msg.what = 5;
						mHandler.sendMessage(msg);
					}
				} else {
					// side出现
					msg.what = 1;
					mHandler.sendMessage(msg);
					mHandler.removeCallbacks(this);
				}
			};
		}, 0);
	}
	
	
	public boolean dispatchTouchEvent(MotionEvent ev) {
		if (View.VISIBLE == sideView.getView().getVisibility() && ev.getX() > xSideLeft) { // 只处理side收起来和side上触摸事件
			int action = ev.getAction();
			
			switch (action) {
				case MotionEvent.ACTION_DOWN:// 按下去
					yMoveSideTop = (int)sideView.getView().getY();
					yMoveSideBottom = sideView.getView().getBottom();
					xMoveStart = (int)ev.getX();
					yMoveStart = (int)ev.getY();
					isSliding = false;
					isMoveOut = false;
					break;
				case MotionEvent.ACTION_MOVE:// 拖动时
					if (!isSliding && Math.abs(ev.getX() - xMoveStart) >= Math.abs(ev.getY() - yMoveStart)) {
						isSliding = true;
					}
					if (isSliding) {		//拖动
//						Log.println(Log.ASSERT, "custom", "left:" + xSideLeft + ", sliding:" + xMoveSideLeft);
						xMoveSideLeft = (int) (xSideLeft + (ev.getX() - xMoveStart));
						if (xMoveSideLeft < xSideLeft) {
							xMoveSideLeft = xSideLeft + 1;  // +1 是为了防止由于计算误差而漏边界
						} else if (xMoveSideLeft > point.x) {
							xMoveSideLeft = point.x;
						}
						moveHandler();
					}
					break;
				case MotionEvent.ACTION_UP:// 放开时
					if (!isMoveOut && (ev.getX() - xMoveStart > 15)) {		// 15而不是0,是为了避免手指微小误差
						isMoveOut = true;
					}
					if (isMoveOut) {		//side收起来
						moveHandler();
					}
					super.dispatchTouchEvent(ev);
					return false;
			}
		}
		return super.dispatchTouchEvent(ev);
	}
	
	public SlidingViewGroup(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		mainView.getView().layout(0, 0, point.x, point.y);
		sideView.getView().layout((int) (point.x * (1 - WIDTH_RATE)), 0, point.x, point.y);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		mainView.getView().measure(widthMeasureSpec, heightMeasureSpec);
		sideView.getView().measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	public boolean isSliding() {
		return isSliding;
	}
	public boolean isMoveOut() {
		return isMoveOut;
	}
	
}


Main.java
package com.testApp5;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class Main {
	
	private Context context;
	private View mainView;
	private ListView listView;
	
	public Main(final Context context, final SlidingViewGroup slidingViewGroup) {
		this.context = context;
		mainView = LayoutInflater.from(context).inflate(R.layout.main, null);
		listView = (ListView) this.mainView.findViewById(R.id.main_list);
		listView.setAdapter(new MainAdapter());
		listView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				Toast.makeText(context, "item_click", Toast.LENGTH_SHORT).show();
				slidingViewGroup.moveHandler();
			}
		});
	}
	
	public View getView() {
		return mainView;
	}
	
	public class MainAdapter extends BaseAdapter {

		@Override
		public int getCount() {
			return mMainStrings.length;
		}

		@Override
		public Object getItem(int position) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public long getItemId(int position) {
			// TODO Auto-generated method stub
			return 0;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			TextView t = new TextView(context);
			t.setTextSize(24);
			t.setPadding(0, 25, 0, 25);
			t.setText(mMainStrings[position]);
			return t;
		}
	}
	
	private String[] mMainStrings = {  
            "感冒", "咳嗽"};
}


Side.java

package com.testApp5;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class Side {
	private View sideView;
	private ListView listView;
	private View footer;
	final private int pageSize = 20;
	private List<String> sideData = new ArrayList<String>();
	private BaseAdapter adapter;
	private boolean canLoad = true;
	private AtomicInteger currentPage = new AtomicInteger(1);
	private SlidingViewGroup slidingViewGroup;
	
	public Side(final Activity activity, final Context context, final SlidingViewGroup slidingViewGroup) {
		setSlidingViewGroup(slidingViewGroup);
		sideView = LayoutInflater.from(context).inflate(R.layout.side, null);
...

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

        <ListView
            android:id="@+id/main_list"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            >
        </ListView>
        
</LinearLayout>

side.xml

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

    <ListView
        android:id="@+id/side_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        >
    </ListView>
        
</LinearLayout>


完成图(点击从右向左展开,再点击从左到右收起来,也可通过拖动把菜单收起来


有空可以参考一下:http://www.cnblogs.com/gzggyy/p/3182472.htmlhttp://www.linuxidc.com/Linux/2013-05/83724.htm



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值