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

最后更新于:2022-04-01 15:47:44

本文来自[http://blog.csdn.net/hellogv/](http://blog.csdn.net/hellogv/) ,欢迎转摘,引用必须注明出处!              上次介绍了[基础篇](http://blog.csdn.net/hellogv/article/details/6789698),讲解了自定义抽屉控件的基础实现,这次就在基础篇的基础上加入拖拉功能。拖拉功能基于GestureDetector,GestureDetector的基本使用方式不是本文介绍的重点,有兴趣的童鞋可以上网查询相关的教程。        本文的抽屉控件相对于基础篇的抽屉控件多了以下功能: > 1.支持手势拖拉 > 2.拖拉到一半时,可以自动展开或者收缩。 具体如下图: > ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-06-24_576cb0a84c3f1.gif) >   > >   本文的源码可以到这里下载:[http://download.csdn.net/detail/hellogv/3642418](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) {} } ~~~    
';