本文來自[http://blog.csdn.net/hellogv/](http://blog.csdn.net/hellogv/) ,歡迎轉摘,引用必須注明出處!??????
?????? 上次介紹了[基礎篇](http://blog.csdn.net/hellogv/article/details/6789698),講解了自定義抽屜控件的基礎實現,這次就在基礎篇的基礎上加入拖拉功能。拖拉功能基于GestureDetector,GestureDetector的基本使用方式不是本文介紹的重點,有興趣的童鞋可以上網查詢相關的教程。
?????? 本文的抽屜控件相對于基礎篇的抽屜控件多了以下功能:
> 1.支持手勢拖拉
> 2.拖拉到一半時,可以自動展開或者收縮。
具體如下圖:
> 
> ?
>
>
?
本文的源碼可以到這里下載:[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) {}
}
~~~
?
?
- 前言
- Android提高第一篇之MediaPlayer
- Android提高第二篇之SurfaceView的基本使用
- Android提高第三篇之SurfaceView與多線程的混搭
- Android提高第四篇之Activity+Intent
- Android提高第五篇之Service
- Android提高第六篇之BroadcastReceiver
- Android提高第七篇之XML解析與生成
- Android提高第八篇之SQLite分頁讀取
- Android提高第九篇之SQLite分頁表格
- Android提高第十篇之AudioRecord實現&quot;助聽器&quot;
- Android提高第十一篇之模擬信號示波器
- Android提高第十二篇之藍牙傳感應用
- Android提高第十三篇之探秘藍牙隱藏API
- Android提高第十四篇之探秘TelephonyManager
- Android提高第十五篇之ListView自適應實現表格
- Android提高十六篇之使用NDK把彩圖轉換灰度圖
- Android上使用ASIFT實現對視角變化更魯棒的特征匹配
- 在Android上使用ZXing識別條形碼/二維碼
- Android提高十七篇之多級樹形菜單的實現
- Android-opencv之CVCamera
- Android提高十八篇之自定義Menu(TabMenu)
- Android提高第十九篇之&quot;多方向&quot;抽屜
- Android提高第二十篇之MediaPlayer播放網絡音頻
- Android提高第二十一篇之MediaPlayer播放網絡視頻
- android平板上的GridView視圖緩存優化
- 精確監聽AbsListView滾動至底部
- 可動態布局的Android抽屜之基礎
- 可動態布局的Android抽屜之完整篇
- Android MediaPlayer與Http Proxy結合之基礎篇