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;

}


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值