3.安卓自定義左右菜單

學習完極客學院的自定義左右菜單,在此記錄。


效果如下:





1.自定義一個類MainUI繼承自RelativeLayout

2.定義三個FrameLayout 分別代表左菜單、當前顯示區域、右菜單。

private FrameLayout leftMenu;
private FrameLayout middleMenu;
private FrameLayout rightMenu;

3.寫一個初始化方法將各個控件初始化並調用addView方法加載到MainUI上,記得爲每個控件設置id,當然要在各個構造方法中調用初始化方法

public static final int LEFT_ID = 0xaabbcc;
public static final int MIDEELE_ID = 0xaaccbb;
public static final int RIGHT_ID = 0xccbbaa;


private void initView(Context context) {
// TODO Auto-generated method stub
this.context = context;
mScroller = new Scroller(context, new DecelerateInterpolator());
leftMenu = new FrameLayout(context);
rightMenu = new FrameLayout(context);
middleMenu = new FrameLayout(context);
middleMask  = new FrameLayout(context);
leftMenu.setBackgroundColor(0x8851a9ea);
rightMenu.setBackgroundColor(0x8851a9ea);
middleMenu.setBackgroundColor(0x88b7ab96);
middleMask.setBackgroundColor(0x88000000);
leftMenu.setId(LEFT_ID);
rightMenu.setId(RIGHT_ID);
middleMenu.setId(MIDEELE_ID);
addView(leftMenu);
addView(middleMenu);
addView(rightMenu);
addView(middleMask);
middleMask.setAlpha(0);
}

4.重寫onMeasure方法爲leftMenu,middleMenu,rightMenu設置大小

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
middleMenu.measure(widthMeasureSpec, heightMeasureSpec);
middleMask.measure(widthMeasureSpec, heightMeasureSpec);
int realWidth = MeasureSpec.getSize(widthMeasureSpec);
int tempWidthMeasure = MeasureSpec.makeMeasureSpec((int)(realWidth * 0.8f), MeasureSpec.EXACTLY);
leftMenu.measure(tempWidthMeasure, heightMeasureSpec);
rightMenu.measure(tempWidthMeasure, heightMeasureSpec);
}

5.重寫onLayout方法爲leftMenu,middleMenu,rightMenu設置位置,都是左--上--右--下(其中上下都是相同的,注意leftMenu,rightMenu左右怎麼得來的)

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
middleMenu.layout(l, t, r, b);
middleMask.layout(l, t, r, b);
leftMenu.layout(l-leftMenu.getMeasuredWidth(), t, r, b);
rightMenu.layout(l+middleMenu.getMeasuredWidth(), t, l + middleMenu.getMeasuredWidth()
+ rightMenu.getMeasuredWidth(), b);
}

6.因爲涉及到滑動事件,定義一個Scroller對象並在初始化方法中初始化

private Scroller mScroller;

7.重寫dispatchTouchEvent監聽滑動事件。首先判斷是點擊還是滑動,距離超過TEST_DIS則判斷爲滑動,否則則爲點擊;然後判斷是否爲左右滑動,顯然上下滑動左右菜單並不會出現。

private boolean isTestCompete; //測試點擊還是滑動
private boolean isleftrightEvent; //測試是否爲左右滑動
private Point point = new Point();
private static final int TEST_DIS = 20;

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(!isTestCompete){
getEventType(ev);
return true;
}
if(isleftrightEvent){
switch(ev.getActionMasked()){
case MotionEvent.ACTION_MOVE:
int curScrollX = getScrollX();//滑動距離
int dis_x = (int)(ev.getX() - point.x);//手指滑動距離+TEST_DIS=滑動距離
int expectX = -dis_x + curScrollX;
int finalX = 0;
if(expectX < 0){//向左滑動
finalX = Math.max(expectX, -leftMenu.getMeasuredWidth());
}else{//向右滑動
finalX = Math.min(expectX, rightMenu.getMeasuredWidth());
}
scrollTo(finalX, 0);
point.x = (int)ev.getX();
break;
case MotionEvent.ACTION_UP://手指擡起
case MotionEvent.ACTION_CANCEL://滑出邊界
//這兩個事件發生時,需要根據左右菜單滑出的多少確定執行的操作(超過則全部滑出,否則退回原有狀態)
curScrollX = getScrollX();
if(Math.abs(curScrollX) > leftMenu.getMeasuredWidth() >> 1){//超過一半 全部滑出
if(curScrollX < 0){//向左滑 右菜單出現
mScroller.startScroll(curScrollX, 0, -leftMenu.getMeasuredWidth() - curScrollX, 0, 200);
}else{//向右滑 左菜單出現
mScroller.startScroll(curScrollX, 0, leftMenu.getMeasuredWidth() - curScrollX, 0, 200);
}
}else{//沒超過一半 返回原樣
mScroller.startScroll(curScrollX, 0, -curScrollX, 0, 200);
}
invalidate();//重繪
//標識置爲false
isleftrightEvent = false;
isTestCompete = false;
break;
}
}else{//否則爲上下滑動,只需將標誌位置爲false
switch(ev.getActionMasked()){
case MotionEvent.ACTION_UP:
isleftrightEvent = false;
isTestCompete = false;
break;
default:
break;
}
}
return super.dispatchTouchEvent(ev);
}


其中的

private void getEventType(MotionEvent ev) {//確定事件的類型
// TODO Auto-generated method stub
switch (ev.getActionMasked()){
case MotionEvent.ACTION_DOWN:
point.x = (int)ev.getX();
point.y = (int)ev.getY();
super.dispatchTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
int dX = Math.abs((int)ev.getX() - point.x);
int dY = Math.abs((int)ev.getY() - point.y);
if(dX >= TEST_DIS && dX > dY){//左右滑動
isleftrightEvent = true;
isTestCompete = true;
point.x = (int)ev.getX();
point.y = (int)ev.getY();
}else if(dY >= TEST_DIS && dY >dX){//上下滑動
isleftrightEvent = false;
isTestCompete = true;
point.x = (int)ev.getX();
point.y = (int)ev.getY();
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
super.dispatchTouchEvent(ev);
isleftrightEvent = false;
isTestCompete = false;
break;
}
}

重寫scrollTo方法是爲了讓middleMask的alpha值由透明逐漸變深,因爲middleMask與middleMenu重合(最開始透明),這樣相當於增加滑動時顯示的特效

@Override
public void scrollTo(int x, int y) {
// TODO Auto-generated method stub
super.scrollTo(x, y);
onMiddleMask();
int curX = Math.abs(getScrollX());
float scale = curX / (float)leftMenu.getMeasuredWidth();
middleMask.setAlpha(scale);
}


8.最後在MainActivity中使用,getSupportFragmentManager().beginTransaction().add(MainUI.LEFT_ID, left).commit();爲左右菜單添加子控件

public class MainActivity extends FragmentActivity {


private MainUI mainUI;
private leftMenu left;
private rightMenu right;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainUI = new MainUI(this);
setContentView(mainUI);
left = new leftMenu();
right = new rightMenu();
getSupportFragmentManager().beginTransaction().add(MainUI.LEFT_ID, left).commit();
getSupportFragmentManager().beginTransaction().add(MainUI.RIGHT_ID, right).commit();
}
}


其中leftMenu

public class leftMenu extends Fragment {


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
View v = inflater.inflate(R.layout.left, container, false);
v.findViewById(R.id.button1).setOnClickListener(new OnClickListener(){


@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i("width", "left");
}

});

return v;

}


}

發佈了25 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章