import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by on 2019/7/12.
*/
public class SoundDistribution extends View {
private Paint mAxisPaint;// 坐标轴画笔
private Paint mValuePaint;// 数值画笔
private Paint mCenterOutPaint;// 中心点外层画笔
private Paint mCenterInPaint;// 中心点内层画笔
private Paint mBackgroundPaint;// 背景色画笔
private int mIViewWidth = 500;// 视图宽度
private int mIViewHeight = 500;// 视图高度
private int mICenterOutRadius = 15;// 中心点外层圆半径
private int mICenterInRadius = 10;// 中心点内层圆半径
private int mICenterX = 0;// 中心点的X坐标
private int mICenterY = 0;// 中心点的Y坐标
private int mIXCopies = 20;// X轴所分的份数
private int mIYCopies = 20;// Y轴所分的份数
private int mIAxisCenterX;// 坐标轴坐标原点X坐标
private int mIAxisCenterY;// 坐标轴坐标原点Y坐标
private int mIXValue = 0;// 设置的X轴平衡值
private int mIYValue = 0;// 设置的Y轴平衡值
private OnPositonChangeListener mOnPositonChangeListener = null;
public interface OnPositonChangeListener {
void onPositionChanged(int x, int y);
void onStartTrackingTouch();
void onStopTrackingTouch();
}
public SoundDistribution(Context context) {
super(context);
init(context);
}
public SoundDistribution(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public SoundDistribution(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
/**
* 初始化
*
* @param context
*/
private void init(Context context) {
mAxisPaint = new Paint();
mAxisPaint.setColor(Color.parseColor("#20b2aa"));
mAxisPaint.setAntiAlias(true);
mAxisPaint.setStyle(Paint.Style.STROKE);
mAxisPaint.setStrokeWidth(1.0f);
mValuePaint = new Paint();
mValuePaint.setAntiAlias(true);
mValuePaint.setStyle(Paint.Style.STROKE);
mValuePaint.setTextSize(20.0f);
mValuePaint.setColor(Color.WHITE);
mValuePaint.setStrokeWidth(1.0f);
mCenterOutPaint = new Paint();
mCenterOutPaint.setAntiAlias(true);
mCenterOutPaint.setStyle(Paint.Style.FILL);
mCenterOutPaint.setColor(Color.parseColor("#cd5c5c"));
mCenterOutPaint.setStrokeWidth(1.0f);
mCenterInPaint = new Paint();
mCenterInPaint.setAntiAlias(true);
mCenterInPaint.setStyle(Paint.Style.FILL);
mCenterInPaint.setColor(Color.parseColor("#ff0000"));
mCenterInPaint.setStrokeWidth(1.0f);
mBackgroundPaint = new Paint();
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setStyle(Paint.Style.FILL);
mBackgroundPaint.setColor(Color.GRAY);
mBackgroundPaint.setStrokeWidth(1.0f);
mIAxisCenterX = (mICenterOutRadius + (mIViewWidth - 2 * mICenterOutRadius) / 2);
mIAxisCenterY = (mICenterOutRadius + (mIViewHeight - 2 * mICenterOutRadius) / 2);
mICenterX = (mICenterOutRadius + (mIViewWidth - 2 * mICenterOutRadius) / 2);
mICenterY = (mICenterOutRadius + (mIViewHeight - 2 * mICenterOutRadius) / 2);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 获取View布局的宽度和高度
mIViewWidth = MeasureSpec.getSize(widthMeasureSpec);
mIViewHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
mIAxisCenterX = (mICenterOutRadius + (mIViewWidth - 2 * mICenterOutRadius) / 2);
mIAxisCenterY = (mICenterOutRadius + (mIViewHeight - 2 * mICenterOutRadius) / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(0, 0, mIViewWidth, mIViewHeight, mBackgroundPaint);
// X轴
canvas.drawLine(mICenterOutRadius, mIAxisCenterY,
mIViewWidth - mICenterOutRadius, mIAxisCenterY, mAxisPaint);
// Y轴
canvas.drawLine(mIAxisCenterX, mICenterOutRadius,
mIAxisCenterX, mIViewHeight - mICenterOutRadius, mAxisPaint);
// 坐标值
float minValueLength = mValuePaint.measureText("-10");
float maxValueLength = mValuePaint.measureText("10");
float originValueLength = mValuePaint.measureText("0");
// X轴最小值
canvas.drawText("-10", mICenterOutRadius, mIAxisCenterY + (mIViewHeight - 2 * mICenterOutRadius) / mIYCopies, mValuePaint);
// Y轴最小值
canvas.drawText("-10", mIAxisCenterX + (mIViewWidth - 2 * mICenterOutRadius) / mIXCopies - minValueLength / 2, (mIViewHeight - mICenterOutRadius), mValuePaint);
// Y轴最大值
canvas.drawText("10", mIAxisCenterX + mICenterOutRadius - maxValueLength / 2, mICenterOutRadius + maxValueLength / 2, mValuePaint);
// X轴最大值
canvas.drawText("10", mIViewWidth - mICenterOutRadius - maxValueLength, mIAxisCenterY + (mIViewHeight - 2 * mICenterOutRadius) / mIYCopies, mValuePaint);
// 0 的显示
canvas.drawText("0", mIAxisCenterX + mICenterOutRadius - originValueLength / 2, mIAxisCenterY - mICenterOutRadius, mValuePaint);
// 外层圆
canvas.drawCircle(mICenterX, mICenterY, mICenterOutRadius, mCenterOutPaint);
// 内层圆
canvas.drawCircle(mICenterX, mICenterY, mICenterInRadius, mCenterInPaint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float eventX = event.getX();
float eventY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (null != mOnPositonChangeListener) {
mOnPositonChangeListener.onStartTrackingTouch();
}
seekTo(eventX, eventY);
break;
case MotionEvent.ACTION_MOVE:
seekTo(eventX, eventY);
break;
case MotionEvent.ACTION_UP:
if (null != mOnPositonChangeListener) {
mOnPositonChangeListener.onStopTrackingTouch();
}
seekTo(eventX, eventY);
break;
}
return true;
}
/**
* 拖拽移动小圆点
*
* @param eventX
* @param eventY
*/
private void seekTo(float eventX, float eventY) {
if (eventX < mICenterOutRadius) {
mICenterX = mICenterOutRadius;
} else if (eventX > mIViewWidth - mICenterOutRadius) {
mICenterX = mIViewWidth - mICenterOutRadius;
} else {
mICenterX = (int) eventX;
invalidate();
}
if (eventY < mICenterOutRadius) {
mICenterY = mICenterOutRadius;
} else if (eventY > mIViewHeight - mICenterOutRadius) {
mICenterY = mIViewHeight - mICenterOutRadius;
} else {
mICenterY = (int) eventY;
invalidate();
}
mIXValue = (mICenterX - mICenterOutRadius) / ((mIViewWidth - 2 * mICenterOutRadius) / mIXCopies);
mIYValue = (mICenterY - mICenterOutRadius) / ((mIViewHeight - 2 * mICenterOutRadius) / mIYCopies);
if (null != mOnPositonChangeListener) {
mOnPositonChangeListener.onPositionChanged(mIXValue - mIXCopies / 2, -(mIYValue - mIYCopies / 2));
}
System.out.println("***********************************" + "mIXValue" + (mIXValue - mIXCopies / 2) + "mIYValue" + (-(mIYValue - mIYCopies / 2)));
}
/**
* 判断点击的位置是否在View上
*
* @param view 需要判断范围的视图
* @param eventX 触摸事件
* @param eventY 触摸事件
* @return 是否点击在View上
*/
private boolean inRangeOfView(View view, float eventX, float eventY) {
int[] location = new int[2];
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
if (eventX < x || eventX > (x + view.getWidth()) || eventY < y || eventY > (y + view.getHeight())) {
return false;
}
return true;
}
/**
* 初始化设置小圆点显示位置
*
* @param x x轴坐标
* @param y y轴坐标
*/
public void setSoundDistribution(int x, int y) {
if (x < 0) {
x = 0;
} else if (x >= mIXCopies) {
x = mIXCopies;
}
if (y < 0) {
y = 0;
} else if (y > mIYCopies) {
y = mIYCopies;
}
mICenterX = mICenterOutRadius + x * ((mIViewWidth - 2 * mICenterOutRadius) / mIXCopies);
mICenterY = mICenterOutRadius + y * ((mIViewHeight - 2 * mICenterOutRadius) / mIYCopies);
invalidate();
}
}
<com.myview.SoundDistribution
android:id="@+id/sd_settings_sound_distribution"
android:layout_width="@dimen/dp_500"
android:layout_height="@dimen/dp_500"
android:layout_below="@+id/tv_settings_sound_distribution_title"/>
没啥复杂的,就是简单的数学计算,整个视图的android 坐标系是从左上角的原点开始的,图中x轴和y轴交汇的原点是上面的
mIAxisCenterX 和 mIAxisCenterY。
刚才测试发现,如果设置View的宽高不为500,初始化圆点的位置不正确,现在还不知道怎么解决 ,只能是直接修改MIViewWidth和mIViewHeight的初始值。
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SoundDistribution, 0, 0);
mIViewWidth = a.getResourceId(R.styleable.SoundDistribution_width, 0);
mIViewHeight = a.getResourceId(R.styleable.SoundDistribution_height, 0);
a.recycle();
xmlns:app=”http://schemas.android.com/apk/res-auto”
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SoundDistribution">
<attr name="width" format="dimension"/>
<attr name="height" format="dimension" />
</declare-styleable>
</resources>