半圆形菜单按钮的简单实现
半圆菜单按钮的简单实现
回调接口代码:
一、应用场景
前段时间一位老友跟我提了一个附在边上的菜单按钮,这段时间比较忙,没有完美实现,只做了个原型Demo出来,先发出来记录一下,到有时间在优化这个View,如果有高手能修改优化分享出来的话,小弟在此谢过了。也赶在这个月底要出一个博文,不能荒废了这个技能~_~。成功在于坚持!废话又吹了半天,来看下需求原型图。
二、分析
个人认为这种按钮一般可以放两个到四个选择,应该是比较好的体验,超出这个范围的话,我觉得用这个方式就不行了。而且Android里面的空间都是方形的,只是加了透明的背景让我们看不出来而已 。技术上的话,这个按钮用到了一个环形,我们分拆一下的话就是几个圆的叠加。上个效果图大家看下先。
三、实现拆分图
1、画一个小圆和一个大一点的圆就可以变成1图所示,然后我们给小圆描一个大边,描边是什么不懂的去搜一下,给大圆秒一个小一点的边,就可以变成图3所示
2、图2就是两个圆的描边的效果,把图2的两种效果叠加起来就是图3的效果,有的图3我们的感觉就出来了
3、我们有了图3的效果后裁剪一下画布,截个1/4出来就有了图4的效果,然后我们在根据背景颜色画上分割线,整个菜单按钮就O了
四、代码实现
上干货,代码都是根据上面的思路画出来的,加上注解问题应该不大了
主要的View代码:
package com.spring.circle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
/**
* 半圆的菜单
* @author spring
*
*/
public class CircleButton extends View {
public CircleButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public CircleButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CircleButton(Context context) {
super(context);
init(context);
}
/**
* 画笔
*/
private Paint paint;
/**
* View的大小
*/
private RectF viewRectF;
/**
* 小圆
*/
private float radius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 95, getResources().getDisplayMetrics());
/**
* 大圆
*/
private float bgRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 95, getResources().getDisplayMetrics());
/**
* 描边
*/
private float strokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 40, getResources().getDisplayMetrics());
/**
* 描边
*/
private float bgStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getResources().getDisplayMetrics());
/**
* 线的大小
*/
private float line = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
/**
* 菜单
*/
private String[] menu = null;
/**
* 背景颜色
*/
private int bgColor = Color.YELLOW;
/**
* 前景颜色
*/
private int color = Color.GREEN;
/**
* 字体的大小
*/
private float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 18, getResources().getDisplayMetrics());
/**
* 字体颜色
*/
private int textColor = Color.WHITE;
/**
* View的区域
*/
private float size = bgRadius+bgStrokeWidth;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension((int)size, (int)size);
}
/**
* init
* @param context
*/
private void init(Context context){
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(radius);
viewRectF = new RectF(0, 0, size, size);
}
/**
* 画一个透明的园然后描上一个很大的边,就变成了一个环
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画背景透明
canvas.drawColor(Color.TRANSPARENT);
//裁剪画布
canvas.clipRect(viewRectF);
paint.setColor(bgColor);
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.STROKE);
//加上描边
paint.setStrokeWidth(bgStrokeWidth);
//画园
canvas.drawCircle(0, size, bgRadius, paint);
paint.setColor(color);
paint.setStrokeWidth(strokeWidth);
canvas.drawCircle(0, size, radius, paint);
if(menu!=null && menu.length>0){
int tmp = (int)(90)/menu.length;
//画文字
for (int i=0;i<menu.length;i++) {
canvas.save();
canvas.rotate(tmp/2+tmp*i,0,size);
paint.reset();
paint.setTextAlign(Align.CENTER);
paint.setColor(textColor);
paint.setTextSize(textSize);
canvas.drawText(menu[i], 0, size-radius, paint);
canvas.restore();
}
//画分隔线
for (int i=0;i<menu.length;i++) {
canvas.save();
canvas.rotate(tmp*i,0,size);
paint.reset();
paint.setAntiAlias(true);
paint.setColor(bgColor);
paint.setStrokeWidth(line);
canvas.drawLine(0, size-bgRadius+bgStrokeWidth/2, 0, size-bgRadius-bgStrokeWidth/2+line*2, paint);
canvas.restore();
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
//检查点击是否在环上
check(event);
break;
}
return true;
}
/**
* 计算长度
* @param x
* @param y
*/
private boolean checkdis(float x, float y) {
double dis = Math.sqrt(x*x+(y-size)*(y-size));
if(dis<radius+strokeWidth/2 && dis>radius-strokeWidth/2)
return true;
else
return false;
}
/**
* 回调接口
*/
private CircleClickListener listener = null;
public void setOnClick(CircleClickListener listener){
this.listener = listener;
}
private void check(MotionEvent event) {
double d = Math.toDegrees(Math.atan((size-event.getY())/(event.getX())));
if(!checkdis(event.getX(),event.getY()))
return ;
int tmp = 90-(int)d;
//区间大小
int dis = 90/menu.length;
for (int i = 0; i < menu.length; i++) {
if(tmp>dis*i&&tmp<dis*(i+1))
{
if(listener !=null){
listener.onClick(menu[i], i);
}
}
}
}
/**
* 设置菜单
* @param menus
*/
public void setMenu(String[] menus){
this.menu = menus;
invalidate();
}
public int getBgColor() {
return bgColor;
}
/**
* 设置背景的颜色
* @param bgColor
*/
public void setBgColor(int bgColor) {
this.bgColor = bgColor;
}
public int getColor() {
return color;
}
/**
* 设置前景色
* @param color
*/
public void setColor(int color) {
this.color = color;
}
public float getTextSize() {
return textSize;
}
/**
* 设置字体的大小
* @param textSize
*/
public void setTextSize(float textSize) {
this.textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, textSize, getResources().getDisplayMetrics());
}
public int getTextColor() {
return textColor;
}
/**
* 设置字体的颜色
* @param textColor
*/
public void setTextColor(int textColor) {
this.textColor = textColor;
}
}
回调接口代码:
package com.spring.circle;
public interface CircleClickListener {
public void onClick(String str,int position);
}
五、不足
这是在一个View里面画出来的菜单,暂时没有加上各种阴影效果,不然得话加上层次效果会高大上很多,有时间再改。还有一个不足时按下没有效果的变化,我暂时没有想到什么好的办法叠加上去,如果有高手路过,请赐教啊,哈哈。
六、懒人下载地址
猛戳这里