android pie改快捷按钮,Android Browser学习十 快捷菜单模块: PieMenu的实现

今天分享一下PieMenu的实现, 可以理解为在一个Framelayout上绘制一个PieMenu: 代码在PieMenu.java中

其添加到窗口的代码在 PieControlBase中

protected void attachToContainer(FrameLayout container) {

if (mPie == null) {

mPie = new PieMenu(mActivity);

LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,

LayoutParams.MATCH_PARENT);

mPie.setLayoutParams(lp);

populateMenu();//添加pieitem

mPie.setController(this);

}

container.addView(mPie);

}

我们知道这个PieMenu是当用户按住屏幕边缘的时候出现的, 也就是是说应该在Touch的时候show了PieMenu:

看他的Action_down的时候:

if (MotionEvent.ACTION_DOWN == action) {//用户按下屏幕

if ((x > getWidth() - mSlop) || (x 

setCenter((int) x, (int) y); //设置pie的位置

show(true);

return true;//返回true表示将来的move 和up事件都用这个view来处理不用dispatch和intercept了.

}

}

通过show函数就可以把整个Menu显示出来了:

/**

* guaranteed has center set

* @param show

* 显示piemenu

*/

private void show(boolean show) {

mOpen = show;

if (mOpen) {

if (mController != null) {

boolean changed = mController.onOpen();

}

layoutPie();

}

if (!show) {

mCurrentItem = null;

mPieView = null;

}

invalidate();

}

layoutPie会遍历每个item把他绘制到指定的位置, 可以看到核心是使用 path把每个扇形绘制出来的.

private void layoutPie() {//绘制每个pieitem的位置

float emptyangle = (float) Math.PI / 16;//空白间隙

int rgap = 2;

int inner = mRadius + rgap;

int outer = mRadius + mRadiusInc - rgap;

int radius = mRadius;

int gap = 1;

for (int i = 0; i 

int level = i + 1;

float sweep = (float) (Math.PI - 2 * emptyangle) / mCounts[level];//每个pieitem占用的度数 ,总的度数是pi/2

float angle = emptyangle + sweep / 2;//为了使 piememu上下对称

for (PieItem item : mItems) {

if (item.getLevel() == level) {

View view = item.getView();

view.measure(view.getLayoutParams().width,

view.getLayoutParams().height);

int w = view.getMeasuredWidth();//计算其宽度和高度

int h = view.getMeasuredHeight();

int r = inner + (outer - inner) * 2 / 3;//扇形的半径

int x = (int) (r * Math.sin(angle));//使用三角函数 计算其x y的位置

int y = mCenter.y - (int) (r * Math.cos(angle)) - h / 2;

if (onTheLeft()) {//如果是在左边

x = mCenter.x + x - w / 2;

} else {

x = mCenter.x - x - w / 2;

}

view.layout(x, y, x + w, y + h); //设置区位置

float itemstart = angle - sweep / 2;

Path slice = makeSlice(getDegrees(itemstart) - gap,

getDegrees(itemstart + sweep) + gap,

outer, inner, mCenter); //绘制扇形

item.setGeometry(itemstart, sweep, inner, outer, slice);

angle += sweep; //下一个扇形在这个扇形的下一个位置

}

}

inner += mRadiusInc;

outer += mRadiusInc;

}

}

然后就是onDraw进行绘制每个扇形了:

@Override

protected void onDraw(Canvas canvas) {

if (mOpen) {

int state;

if (mUseBackground) {

int w = mBackground.getIntrinsicWidth();

int h = mBackground.getIntrinsicHeight();

int left = mCenter.x - w;

int top = mCenter.y - h / 2;

mBackground.setBounds(left, top, left + w, top + h);

state = canvas.save();

if (onTheLeft()) {

canvas.scale(-1, 1);//翻转

}

mBackground.draw(canvas);

canvas.restoreToCount(state);

}

for (PieItem item : mItems) {//遍历每一个item将其绘制

Paint p = item.isSelected() ? mSelectedPaint : mNormalPaint; //选择选择的画笔还是normal画笔?

state = canvas.save();

if (onTheLeft()) {//如果点击的在左边

canvas.scale(-1, 1);

}

drawPath(canvas, item.getPath(), p);

canvas.restoreToCount(state);//绘制完了回到以前的状态绘制item

drawItem(canvas, item);

}

if (mPieView != null) {//绘制piemenu的sbumenu 比如tab的缩略图

mPieView.draw(canvas);

}

}

}

然后是Move事件了, 在Movel事件的时候会判断用户手指落在哪里了,然后设置那个扇形为选中, 绘制不再赘述

else if (MotionEvent.ACTION_MOVE == action) {

boolean handled = false;

PointF polar = getPolar(x, y);//根据xy 求出点击的那个扇面.

int maxr = mRadius + mLevels * mRadiusInc + 50;

if (mPieView != null) {

handled = mPieView.onTouchEvent(evt);

}

if (handled) {

invalidate();

return false;

}

if (polar.y > maxr) {//可能没有选中, 就恢复以前的状态

deselect();

show(false);

evt.setAction(MotionEvent.ACTION_DOWN);

if (getParent() != null) {

((ViewGroup) getParent()).dispatchTouchEvent(evt);

}

return false;

}

PieItem item = findItem(polar);//根据给定的点 求出点击的那个扇面.

if (mCurrentItem != item) {

onEnter(item);

if ((item != null) && item.isPieView()) {//类型tab, 含有二级的pieview, 就展现那个listview或者其他

int cx = item.getView().getLeft() + (onTheLeft()

? item.getView().getWidth() : 0);

int cy = item.getView().getTop();

mPieView = item.getPieView();

layoutPieView(mPieView, cx, cy,

(item.getStartAngle() + item.getSweep()) / 2);

}

invalidate();

}

}

在用户放开手的时候也就是Up的时候会通知controller 选中了哪个扇形: , 绘制不再赘述

else if (MotionEvent.ACTION_UP == action) {

if (mOpen) {//在手放开的时候如果piemenu在显示那么就开始执行相应的点击操作, 并恢复touch前的状态

boolean handled = false;

if (mPieView != null) {

handled = mPieView.onTouchEvent(evt);

}

PieItem item = mCurrentItem;

deselect();//取消选中

show(false);//关闭menu

if (!handled && (item != null)) {

item.getView().performClick();//相应相关item的点击事件

}

return true;

}

}

完全自绘的viewgroup, 对我们学习还是帮助很大的.Framelayout只是提供了一个"舞台"而已, 所有的绘制和事件处理都是我们自己实现的, 对于一些复杂的需求, 我们可以这样实现.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值