import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;
import java.util.ArrayList;
public class PieView extends View {
private Paint viewPaint;//画扇形和中间圆的画笔
private Paint textPaint;//文字画笔
private ArrayList<String> itemList = new ArrayList<>();
private int weith;//宽
private int height;//高
private float maxAngle;//最大的滑动角度
private Context mContext;
private float angleCha;
private String mainText = "我的空间";
public PieView(Context context) {
super(context);
init(context);
}
public PieView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PieView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
this.mContext = context;
viewPaint = new Paint();
viewPaint.setAntiAlias(true);
viewPaint.setStyle(Paint.Style.FILL);
viewPaint.setColor(Color.GREEN);
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setTextSize(sp2px(18));
textPaint.setTextAlign(Paint.Align.CENTER);
itemList.clear();
itemList.add("外婆家1");
itemList.add("老家2");
itemList.add("奶奶家3");
itemList.add("好多家4");
itemList.add("外婆家5");
itemList.add("老家6");
itemList.add("奶奶家7");
itemList.add("好多家8");
itemList.add("姥姥家9");
itemList.add("姥姥家10");
itemList.add("姥姥家11");
itemList.add("姥姥家12");
itemList.add("我家13");
itemList.add("我家14");
itemList.add("我家15");
itemList.add("我家16");
itemList.add("我家17");
itemList.add("我家18");
itemList.add(". . .");
maxAngle = -30 * (itemList.size() - 6);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
weith = widthSize;
height = weith / 2;
//应用测量值
setMeasuredDimension(weith, height);
}
private int[] angle;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
angle = new int[itemList.size()];
for (int i = 0; i < itemList.size(); i++) {
angle[i] = -75 + 30 * i + (int) recentAcgle;
}
for (int i = 0; i < angle.length; i++) {
if (angle[i] > -105 && angle[i] < 105) {
canvas.save();
canvas.rotate(angle[i], weith / 2, height);
RectF rectF;
if (clickItem == i) {
rectF = new RectF(0, dp2px(5), weith, height * 2 - dp2px(5));
viewPaint.setColor(Color.parseColor("#058586"));
} else {
rectF = new RectF(0, 0, weith, height * 2);
viewPaint.setColor(Color.parseColor("#02fcfd"));
}
canvas.drawArc(rectF, 255, 29, true, viewPaint);
textPaint.setTextSize(sp2px(18));
canvas.drawText(itemList.get(i), weith / 2, height / 6, textPaint);
canvas.restore();
}
}
viewPaint.setColor(Color.WHITE);
RectF rectSmall = new RectF(weith / 6, height / 3, weith * 5 / 6, height * 5 / 3);
canvas.drawArc(rectSmall, 180, 180, true, viewPaint);
RectF rectCenter;
if (clickItem == itemList.size()) {
viewPaint.setColor(Color.parseColor("#058586"));
rectCenter = new RectF(weith / 4 + dp2px(5), height / 2 + dp2px(5), weith * 3 / 4 - dp2px(5), height * 3 / 2 - dp2px(5));
} else {
viewPaint.setColor(Color.parseColor("#02fcfd"));
rectCenter = new RectF(weith / 4, height / 2, weith * 3 / 4, height * 3 / 2);
}
canvas.drawArc(rectCenter, 180, 180, true, viewPaint);
textPaint.setTextSize(sp2px(25));
canvas.drawText(mainText, weith / 2, height - textPaint.getTextSize(), textPaint);
}
float downX = 0;
float downY = 0;
private float recentAcgle;
private float clickAcgle = 0;//当前点击的角度,用于确定当前点击在哪个item中。
private int clickItem = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
viewRuning = false;
mHandler.removeMessages(1);
mHandler.removeMessages(0);
downX = event.getX();
downY = event.getY();
angleCha = 0;
clickAcgle = calcAngle(event.getX(), event.getY()) - 255;
double sqrt = Math.sqrt((downX - weith / 2) * (downX - weith / 2) + (downY - height) * (downY - height));
if (sqrt <= weith / 2 && sqrt >= weith / 3) {
for (int i = 0; i < angle.length; i++) {
if (angle[i] < clickAcgle && angle[i] + 30 > clickAcgle) {
clickItem = i;
break;
}
}
} else if (sqrt <= weith / 4) {
clickItem = itemList.size();
}
mHandler.sendEmptyMessageDelayed(1, 200);
Log.e("onTouchEvent_DOWN", "clickAcgle : " + clickAcgle + " clickItem : " + clickItem);
break;
case MotionEvent.ACTION_MOVE:
angleCha = calcAngle(event.getX(), event.getY()) - calcAngle(downX, downY);
downY = event.getY();
downX = event.getX();
Log.e("onTouchEvent_MOVE", "angleCha : " + angleCha + " clickItem : " + clickItem);
if (Math.abs(angleCha)>=1 &&clickItem >= 0) {
clickItem = -1;
mHandler.removeMessages(1);
}
// 防止越界
if (angleCha < -300) {
angleCha = angleCha + 360;
} else if (angleCha > 300) {
angleCha = angleCha - 360;
}
recentAcgle += angleCha;
if (itemList.size() <= 6) {
if (recentAcgle <= 0) {
recentAcgle = 0;
} else if (recentAcgle >= maxAngle) {
recentAcgle = maxAngle;
}
} else {
if (recentAcgle > 0) {
recentAcgle = 0;
} else if (recentAcgle < maxAngle) {
recentAcgle = maxAngle;
}
}
invalidate();
break;
case MotionEvent.ACTION_UP:
Log.w("onTouchEvent_UP", "angleCha : " + angleCha);
clickAcgle = calcAngle(event.getX(), event.getY()) - 255;
for (int i = 0; i < angle.length; i++) {
Log.w("onTouchEvent_UP", "点击的事件 : "+i +(angle[i] < clickAcgle && angle[i] + 30 > clickAcgle));
if (angle[i] < clickAcgle && angle[i] + 30 > clickAcgle) {
Log.w("onTouchEvent_UP", (clickItem == i)+"........点击的事件 : " + clickItem);
if (clickItem == i) {
Log.w("onTouchEvent_UP", (listener != null)+"点击的事件 : " + clickItem);
if (listener != null) {
listener.ItemClick(clickItem);
}
}
break;
}
}
if (clickItem == itemList.size()) {
if (listener != null) {
listener.MainClick();
}
}
clickItem = -1;
invalidate();
if (itemList.size() > 6 && Math.abs(angleCha) > 1) {
new myThread().start();
}
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
private boolean viewRuning;//
private class myThread extends Thread {
private int time;//时间
private int space;//速度
public myThread() {
viewRuning = true;
}
@Override
public void run() {
super.run();
int i = 0;
while (viewRuning) {
recentAcgle += (float) (angleCha * accelerateItp[i]);
if (recentAcgle >= 0) {
recentAcgle = 0;
viewRuning = false;
break;
}
if (recentAcgle <= maxAngle) {
recentAcgle = maxAngle;
viewRuning = false;
break;
}
i++;
Log.w("myThread", "handleMessage : " + i + " viewRuning : " + Thread.currentThread().getName());
if (viewRuning) {
mHandler.sendEmptyMessage(0);
SystemClock.sleep(10);
}
if (i >= 100) {
viewRuning = false;
}
}
}
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.e("onTouchEvent_mHandler", "handleMessage : " + clickAcgle + " viewRuning : " + viewRuning);
if (msg.what == 0) {
PieView.this.invalidate();
} else if (msg.what == 1) {
PieView.this.invalidate();
}
}
};
/**
* 设置数据
*/
public void setData(ArrayList list, String strText) {
this.mainText = strText;
itemList.clear();
itemList.addAll(list);
recentAcgle = 0;
PieView.this.invalidate();
}
/**
* 数据根据AccelerateDecelerateInterpolator插值器的减速算法得到
* <p>
* public float getInterpolation(float input) {
* return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
* }
*/
private double[] accelerateItp = {1.0000, 0.9998, 0.9990, 0.9978, 0.9961, 0.9938, 0.9911, 0.9880, 0.9843, 0.9801, 0.9755, 0.9704, 0.9649, 0.9589, 0.9524, 0.9455, 0.9382, 0.9304, 0.9222, 0.9135, 0.9045, 0.8951, 0.8853, 0.8751, 0.8645, 0.8536, 0.8423, 0.8307, 0.8187, 0.8065, 0.7939, 0.7810, 0.7679, 0.7545, 0.7409, 0.7270, 0.7129, 0.6986, 0.6841, 0.6694, 0.6545, 0.6395, 0.6243, 0.6091, 0.5937, 0.5782, 0.5627, 0.5471, 0.5314, 0.5157, 0.5000, 0.4843, 0.4686, 0.4529, 0.4373, 0.4218, 0.4063, 0.3909, 0.3757, 0.3605, 0.3455, 0.3306, 0.3159, 0.3014, 0.2871, 0.2730, 0.2591, 0.2455, 0.2321, 0.2190, 0.2061, 0.1935, 0.1813, 0.1693, 0.1577, 0.1464, 0.1355, 0.1249, 0.1147, 0.1049, 0.0955, 0.0865, 0.0778, 0.0696, 0.0618, 0.0545, 0.0476, 0.0411, 0.0351, 0.0296, 0.0245, 0.0199, 0.0157, 0.0120, 0.0089, 0.0062, 0.0039, 0.0022, 0.0010, 0.0002};
/**
* 以按钮圆心为坐标圆点,建立坐标系,求出(targetX, targetY)坐标与x轴的夹角
*
* @param targetX x坐标
* @param targetY y坐标
* @return (targetX, targetY)坐标与x轴的夹角
*/
private float calcAngle(float targetX, float targetY) {
float x = targetX - weith / 2;//len/2 圆点x坐标
float y = targetY - height;//len/2 圆点y坐标
double radian;
if (x != 0) {
float tan = Math.abs(y / x);
if (x > 0) {
if (y >= 0) {
radian = Math.atan(tan);
} else {
radian = 2 * Math.PI - Math.atan(tan);
}
} else {
if (y >= 0) {
radian = Math.PI - Math.atan(tan);
} else {
radian = Math.PI + Math.atan(tan);
}
}
} else {
if (y > 0) {
radian = Math.PI / 2;
} else {
radian = -Math.PI / 2;
}
}
return (float) ((radian * 180) / Math.PI);
}
private int dp2px(float dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dp, getResources().getDisplayMetrics());
}
private int sp2px(float sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
sp, getResources().getDisplayMetrics());
}
public interface ItemClickListener {
void ItemClick(int item);
void MainClick();
}
private ItemClickListener listener;
public void setItemClickListener(ItemClickListener listener) {
this.listener = listener;
}
}
完善中。。。。。