1. 程式人生 > >Android筆記--自定義控件仿遙控器的圓形上下左右OK圓盤按鈕

Android筆記--自定義控件仿遙控器的圓形上下左右OK圓盤按鈕

分享圖片 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圓盤按鈕