Android筆記--自定義控件仿遙控器的圓形上下左右OK圓盤按鈕
阿新 • • 發佈:2018-10-26
分享圖片 https click cas tween .com show idc rotate 原文:Android筆記--自定義控件仿遙控器的圓形上下左右OK圓盤按鈕
上面就是幾張預覽圖!代碼在最底下
主要就兩個步驟,畫圖、監聽點擊
1、整個控件基本上是一步步畫出來的,重寫onDraw方法開始for循環畫扇形出來,畫扇形的時候同時畫扇形內的圖標,扇形畫完了之後畫中心圓按鈕,中心畫了圓之後吧OK按鈕畫上。
2、重寫onTouch方法監聽手指觸發的位置,根據按下的位置確定按鈕在哪個扇形的範圍上,然後重繪一下onDraw把按下的灰色背景繪制出來。難點在於如何確定按下的位置是否處於扇形範圍,換了好幾種方案,奈何數學不好,最後選了現在使用的方案。
package com.imxiaoyu.common.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 仿遙控器上下左右ok圓形菜單
* Created by 龐光渝 on 2017/3/9.博客:https://my.oschina.net/u/1462828/blog
*/
public class RoundMenuView extends View {
/**
* 變量
*/
private int coreX;//中心點的坐標X
private int coreY;//中心點的坐標Y
private List<RoundMenu> roundMenus;//菜單列表
private boolean isCoreMenu = false;//是否有中心按鈕
private int coreMenuColor;//中心按鈕的默認背景--最好不要透明色
private int coreMenuStrokeColor;//中心按鈕描邊顏色
private int coreMenuStrokeSize;//中心按鈕描邊粗細
private int coreMenuSelectColor;//中心按鈕選中時的背景顏色
private Bitmap coreBitmap;//OK圖片
private OnClickListener onCoreClickListener;//中心按鈕的點擊回調
private float deviationDegree;//偏移角度
private int onClickState = -2;//-2是無點擊,-1是點擊中心圓,其他是點擊菜單
private int roundRadius;//中心圓的半徑
private double radiusDistance;//半徑的長度比(中心圓半徑=大圓半徑*radiusDistance)
private long touchTime;//按下時間,擡起的時候判定一下,超過300毫秒算點擊
public RoundMenuView(Context context) {
super(context);
}
public RoundMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public RoundMenuView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onDraw(Canvas canvas) {
coreX = getWidth() / 2;
coreY = getHeight() / 2;
roundRadius = (int) (getWidth()/2 * radiusDistance);//計算中心圓圈半徑
RectF rect = new RectF(0, 0, getWidth(), getHeight());
if (roundMenus != null && roundMenus.size() > 0) {
float sweepAngle = 360 / roundMenus.size();//每個弧形的角度
deviationDegree = sweepAngle / 2;//其實的偏移角度,如果4個扇形的時候是X形狀,而非+,設為0試試就知道什麽意思了
for (int i = 0; i < roundMenus.size(); i++) {
RoundMenu roundMenu = roundMenus.get(i);
//填充
Paint paint = new Paint();
paint.setAntiAlias(true);
if (onClickState == i) {
//選中
paint.setColor(roundMenu.selectSolidColor);
} else {
//未選中
paint.setColor(roundMenu.solidColor);
}
canvas.drawArc(rect, deviationDegree + (i * sweepAngle), sweepAngle, true, paint);
//畫描邊
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(roundMenu.strokeSize);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(roundMenu.strokeColor);
canvas.drawArc(rect, deviationDegree + (i * sweepAngle), sweepAngle, roundMenu.useCenter, paint);
//畫圖案
Matrix matrix = new Matrix();
matrix.postTranslate((float) ((coreX + getWidth() / 2 * roundMenu.iconDistance) - (roundMenu.icon.getWidth() / 2)), coreY - (roundMenu.icon.getHeight() / 2));
matrix.postRotate(((i + 1) * sweepAngle), coreX, coreY);
canvas.drawBitmap(roundMenu.icon, matrix, null);
}
}
//畫中心圓圈
if (isCoreMenu) {
//填充
RectF rect1 = new RectF(coreX - roundRadius, coreY - roundRadius, coreX + roundRadius, coreY + roundRadius);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(coreMenuStrokeSize);
if (onClickState == -1) {
paint.setColor(coreMenuSelectColor);
} else {
paint.setColor(coreMenuColor);
}
canvas.drawArc(rect1, 0, 360, true, paint);
//畫描邊
paint = new Paint();
paint.setAntiAlias(true);
paint.setStrokeWidth(coreMenuStrokeSize);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(coreMenuStrokeColor);
canvas.drawArc(rect1, 0, 360, true, paint);
if (coreBitmap != null) {
//畫中心圓圈的“OK”圖標
canvas.drawBitmap(coreBitmap, coreX - coreBitmap.getWidth() / 2, coreY - coreBitmap.getHeight() / 2, null);//在 0,0坐標開始畫入src
}
}
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchTime = new Date().getTime();
float textX = event.getX();
float textY = event.getY();
int distanceLine = (int) getDisForTwoSpot(coreX, coreY, textX, textY);//距離中心點之間的直線距離
if (distanceLine <= roundRadius) {
//點擊的是中心圓;按下點到中心點的距離小於中心園半徑,那就是點擊中心園了
onClickState = -1;
} else if (distanceLine <= getWidth() / 2) {
//點擊的是某個扇形;按下點到中心點的距離大於中心圓半徑小於大圓半徑,那就是點擊某個扇形了
float sweepAngle = 360 / roundMenus.size();//每個弧形的角度
int angle = getRotationBetweenLines(coreX, coreY, textX, textY);
//這個angle的角度是從正Y軸開始,而我們的扇形是從正X軸開始,再加上偏移角度,所以需要計算一下
angle = (angle + 360 - 90 - (int) deviationDegree) % 360;
onClickState = (int) (angle / sweepAngle);//根據角度得出點擊的是那個扇形
} else {
//點擊了外面
onClickState = -2;
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if ((new Date().getTime() - touchTime) < 300) {
//點擊小於300毫秒算點擊
OnClickListener onClickListener = null;
if (onClickState == -1) {
onClickListener = onCoreClickListener;
} else if (onClickState >= 0 && onClickState < roundMenus.size()) {
onClickListener = roundMenus.get(onClickState).onClickListener;
}
if (onClickListener != null) {
onClickListener.onClick(this);
}
}
onClickState = -2;
invalidate();
break;
}
return true;
}
/**
* 添加菜單
*
* @param roundMenu
*/
public void addRoundMenu(RoundMenu roundMenu) {
if (roundMenu == null) {
return;
}
if (roundMenus == null) {
roundMenus = new ArrayList<>();
}
roundMenus.add(roundMenu);
invalidate();
}
/**
* 添加中心菜單按鈕
*
* @param coreMenuColor
* @param coreMenuSelectColor
* @param onClickListener
*/
public void setCoreMenu(int coreMenuColor, int coreMenuSelectColor, int coreMenuStrokeColor,
int coreMenuStrokeSize, double radiusDistance,Bitmap bitmap, OnClickListener onClickListener) {
isCoreMenu = true;
this.coreMenuColor = coreMenuColor;
this.radiusDistance = radiusDistance;
this.coreMenuSelectColor = coreMenuSelectColor;
this.coreMenuStrokeColor = coreMenuStrokeColor;
this.coreMenuStrokeSize = coreMenuStrokeSize;
coreBitmap = bitmap;
this.onCoreClickListener = onClickListener;
invalidate();
}
/**
* 獲取兩條線的夾角
*
* @param centerX
* @param centerY
* @param xInView
* @param yInView
* @return
*/
public static int getRotationBetweenLines(float centerX, float centerY, float xInView, float yInView) {
double rotation = 0;
double k1 = (double) (centerY - centerY) / (centerX * 2 - centerX);
double k2 = (double) (yInView - centerY) / (xInView - centerX);
double tmpDegree = Math.atan((Math.abs(k1 - k2)) / (1 + k1 * k2)) / Math.PI * 180;
if (xInView > centerX && yInView < centerY) { //第一象限
rotation = 90 - tmpDegree;
} else if (xInView > centerX && yInView > centerY) //第二象限
{
rotation = 90 + tmpDegree;
} else if (xInView < centerX && yInView > centerY) { //第三象限
rotation = 270 - tmpDegree;
} else if (xInView < centerX && yInView < centerY) { //第四象限
rotation = 270 + tmpDegree;
} else if (xInView == centerX && yInView < centerY) {
rotation = 0;
} else if (xInView == centerX && yInView > centerY) {
rotation = 180;
}
return (int) rotation;
}
/**
* 求兩個點之間的距離
*
* @return
*/
public static double getDisForTwoSpot(float x1, float y1, float x2, float y2) {
float width, height;
if (x1 > x2) {
width = x1 - x2;
} else {
width = x2 - x1;
}
if (y1 > y2) {
height = y2 - y1;
} else {
height = y2 - y1;
}
return Math.sqrt((width * width) + (height * height));
}
/**
* 扇形的對象類
*/
public static class RoundMenu {
public boolean useCenter = true;//扇形是否畫連接中心點的直線
public int solidColor = 0x00000000;//背景顏色,默認透明
public int selectSolidColor = 0x00000000;//背景顏色,默認透明
public int strokeColor = 0x00000000;//描邊顏色,默認透明
public int strokeSize = 1;//描邊的寬度,默認1
public Bitmap icon;//菜單的圖片
public OnClickListener onClickListener;//點擊監聽
public double iconDistance = 0.63;//圖標距離中心點的距離
}
}
然後是調用,調用代碼就簡單的放幾句吧,應該看得懂的
RoundMenuView.RoundMenu roundMenu = new RoundMenuView.RoundMenu();
roundMenu.selectSolidColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.strokeColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.icon=ImageUtils.drawable2Bitmap(getActivity(),R.drawable.ic_right);
roundMenu.onClickListener=new OnClickListener() {
@Override
public void onClick(View view) {
ToastUtils.showToast(getActivity(),"點擊了1");
}
};
roundMenuView.addRoundMenu(roundMenu);
roundMenu = new RoundMenuView.RoundMenu();
roundMenu.selectSolidColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.strokeColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.icon=ImageUtils.drawable2Bitmap(getActivity(),R.drawable.ic_right);
roundMenu.onClickListener=new OnClickListener() {
@Override
public void onClick(View view) {
ToastUtils.showToast(getActivity(),"點擊了2");
}
};
roundMenuView.addRoundMenu(roundMenu);
roundMenu = new RoundMenuView.RoundMenu();
roundMenu.selectSolidColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.strokeColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.icon=ImageUtils.drawable2Bitmap(getActivity(),R.drawable.ic_right);
roundMenu.onClickListener=new OnClickListener() {
@Override
public void onClick(View view) {
ToastUtils.showToast(getActivity(),"點擊了3");
}
};
roundMenuView.addRoundMenu(roundMenu);
roundMenu = new RoundMenuView.RoundMenu();
roundMenu.selectSolidColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.strokeColor = ColorUtils.getColor(getActivity(), R.color.gray_9999);
roundMenu.icon=ImageUtils.drawable2Bitmap(getActivity(),R.drawable.ic_right);
roundMenu.onClickListener=new OnClickListener() {
@Override
public void onClick(View view) {
ToastUtils.showToast(getActivity(),"點擊了4");
}
};
roundMenuView.addRoundMenu(roundMenu);
roundMenuView.setCoreMenu(ColorUtils.getColor(getActivity(), R.color.gray_f2f2),
ColorUtils.getColor(getActivity(), R.color.gray_9999), ColorUtils.getColor(getActivity(), R.color.gray_9999)
, 1, 0.43,ImageUtils.drawable2Bitmap(getActivity(),R.drawable.ic_ok), new OnClickListener() {
@Override
public void onClick(View view) {
ToastUtils.showToast(getActivity(),"點擊了中心圓圈");
}
});
?
http://doutugongchang.com
Android筆記--自定義控件仿遙控器的圓形上下左右OK圓盤按鈕