`
yuanlanjun
  • 浏览: 1184959 次
文章分类
社区版块
存档分类
最新评论

可动态布局的Android抽屉之完整篇

 
阅读更多

本文来自http://blog.csdn.net/hellogv/ ,欢迎转摘,引用必须注明出处!

上次介绍了基础篇,讲解了自定义抽屉控件的基础实现,这次就在基础篇的基础上加入拖拉功能。拖拉功能基于GestureDetector,GestureDetector的基本使用方式不是本文介绍的重点,有兴趣的童鞋可以上网查询相关的教程。

本文的抽屉控件相对于基础篇的抽屉控件多了以下功能:

1.支持手势拖拉

2.拖拉到一半时,可以自动展开或者收缩。
具体如下图:

本文的源码可以到这里下载:http://download.csdn.net/detail/hellogv/3642418

只贴出抽屉组件的源码,其他源文件与基础篇的一样:

public class Panel extends LinearLayout implements GestureDetector.OnGestureListener{
	
	public interface PanelClosedEvent {
		void onPanelClosed(View panel);
	}
	
	public interface PanelOpenedEvent {
		void onPanelOpened(View panel);
	}
	
	private final static int HANDLE_WIDTH=30;
	private final static int MOVE_WIDTH=20;
	private Button btnHandler;
	private LinearLayout panelContainer;
	private int mRightMargin=0;
	private Context mContext;
	private GestureDetector mGestureDetector;
	private boolean mIsScrolling=false;
	private float mScrollX;
	private PanelClosedEvent panelClosedEvent=null;
	private PanelOpenedEvent panelOpenedEvent=null;
	
	public Panel(Context context,View otherView,int width,int height) {
		super(context);
		this.mContext=context;
		
		//定义手势识别
		mGestureDetector = new GestureDetector(mContext,this);
		mGestureDetector.setIsLongpressEnabled(false);
		
		//改变Panel附近组件的属性
		LayoutParams otherLP=(LayoutParams) otherView.getLayoutParams();
		otherLP.weight=1;
		otherView.setLayoutParams(otherLP);
		
		//设置Panel本身的属性
		LayoutParams lp=new LayoutParams(width, height);
		lp.rightMargin=-lp.width+HANDLE_WIDTH;
		mRightMargin=Math.abs(lp.rightMargin);
		this.setLayoutParams(lp);
		this.setOrientation(LinearLayout.HORIZONTAL);
		
		//设置Handler的属性
		btnHandler=new Button(context);
		btnHandler.setLayoutParams(new LayoutParams(HANDLE_WIDTH,height));
		//btnHandler.setOnClickListener(handlerClickEvent);
		btnHandler.setOnTouchListener(handlerTouchEvent);
		this.addView(btnHandler);
		
		//设置Container的属性
		panelContainer=new LinearLayout(context);
		panelContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.FILL_PARENT));
		this.addView(panelContainer);

	}

	private View.OnTouchListener handlerTouchEvent=new View.OnTouchListener() {
		
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			if(event.getAction()==MotionEvent.ACTION_UP && //onScroll时的ACTION_UP
					mIsScrolling==true)
			{
				LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
				if (lp.rightMargin >= (-mRightMargin/2)) {//往左超过一半
					new AsynMove().execute(new Integer[] { MOVE_WIDTH });// 正数展开
				} 
				else if (lp.rightMargin < (-mRightMargin/2)) {//往右拖拉
					new AsynMove().execute(new Integer[] { -MOVE_WIDTH });// 负数收缩
				}
			}
			return mGestureDetector.onTouchEvent(event); 
		}
	};

	/**
	 * 定义收缩时的回调函数
	 * @param event
	 */
	public void setPanelClosedEvent(PanelClosedEvent event)
	{
		this.panelClosedEvent=event;
	}
	
	/**
	 * 定义展开时的回调函数
	 * @param event
	 */
	public void setPanelOpenedEvent(PanelOpenedEvent event)
	{
		this.panelOpenedEvent=event;
	}
	
	/**
	 * 把View放在Panel的Container
	 * @param v
	 */
	public void fillPanelContainer(View v)
	{
		panelContainer.addView(v);
	}
	
	/**
	 * 异步移动Panel
	 * @author hellogv 
	 */
	class AsynMove extends AsyncTask<Integer, Integer, Void> {

		@Override
		protected Void doInBackground(Integer... params) {
			int times;
			if (mRightMargin % Math.abs(params[0]) == 0)// 整除
				times = mRightMargin / Math.abs(params[0]);
			else
				// 有余数
				times = mRightMargin / Math.abs(params[0]) + 1;

			for (int i = 0; i < times; i++) {
				publishProgress(params);
				try {
					Thread.sleep(Math.abs(params[0]));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Integer... params) {
			LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
			if (params[0] < 0)
				lp.rightMargin = Math.max(lp.rightMargin + params[0],
						(-mRightMargin));
			else
				lp.rightMargin = Math.min(lp.rightMargin + params[0], 0);

			if(lp.rightMargin==0 && panelOpenedEvent!=null){//展开之后
				panelOpenedEvent.onPanelOpened(Panel.this);//调用OPEN回调函数
			}
			else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){//收缩之后
				panelClosedEvent.onPanelClosed(Panel.this);//调用CLOSE回调函数
			}
			Panel.this.setLayoutParams(lp);
		}
	}

	@Override
	public boolean onDown(MotionEvent e) {
		mScrollX=0;
		mIsScrolling=false;
		return false;
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		LayoutParams lp = (LayoutParams) Panel.this.getLayoutParams();
		if (lp.rightMargin < 0)// CLOSE的状态
			new AsynMove().execute(new Integer[] { MOVE_WIDTH });// 正数展开
		else if (lp.rightMargin >= 0)// OPEN的状态
			new AsynMove().execute(new Integer[] { -MOVE_WIDTH });// 负数收缩
		return false;
	}
	
	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY) {
		mIsScrolling=true;
		mScrollX+=distanceX;
		
		LayoutParams lp=(LayoutParams) Panel.this.getLayoutParams();
		if (lp.rightMargin < -1 && mScrollX > 0) {//往左拖拉
			lp.rightMargin = Math.min((lp.rightMargin + (int) mScrollX),0);
			Panel.this.setLayoutParams(lp);
			Log.e("onScroll",lp.rightMargin+"");
		} 
		else if (lp.rightMargin > -(mRightMargin) && mScrollX < 0) {//往右拖拉
			lp.rightMargin = Math.max((lp.rightMargin + (int) mScrollX),-mRightMargin);
			Panel.this.setLayoutParams(lp);
		}
		
		if(lp.rightMargin==0 && panelOpenedEvent!=null){//展开之后
			panelOpenedEvent.onPanelOpened(Panel.this);//调用OPEN回调函数
		}
		else if(lp.rightMargin==-(mRightMargin) && panelClosedEvent!=null){//收缩之后
			panelClosedEvent.onPanelClosed(Panel.this);//调用CLOSE回调函数
		}
		Log.e("onScroll",lp.rightMargin+"");
		
		return false;
	}
	
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY) {return false;}
	@Override
	public void onLongPress(MotionEvent e) {}
	@Override
	public void onShowPress(MotionEvent e) {}

}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics