我在视图上绘制了一组点,如下图所示。
详细信息:
我有一个x和y坐标数组。但问题是它不能根据不同的屏幕分辨率进行调整。
我想要的是什么:
我希望它独立于屏幕位于视图的中心 分辨率。
这是我的代码:
public class FirstFragment extends Fragment implements Step {
int[] y = {381, 379, 372, 351, 329, 305, 269, 230, 195, 156, 117, 95, 64, 44, 24, 15, 13, 25, 46, 72, 107, 128, 162, 195, 222, 244, 266, 298, 324, 341, 363, 372, 378, 376, 363, 339, 308, 281, 263, 246, 237, 235, 244, 259, 274, 298, 318, 334, 353, 383, 414, 443, 467, 490, 512, 538, 562, 582, 596, 604, 602, 586, 562, 532, 510, 485, 461, 439, 414, 391, 365, 344, 322, 305, 262, 246, 235, 234, 241, 257, 279, 306, 335, 359, 375, 381};
int[] x = {93, 109, 130, 157, 181, 207, 253, 297, 336, 380, 406, 413, 415, 405, 381, 358, 326, 296, 272, 261, 266, 274, 301, 336, 368, 397, 423, 461, 487, 508, 540, 562, 587, 613, 639, 658, 666, 659, 647, 629, 607, 583, 559, 527, 496, 461, 444, 425, 406, 375, 339, 313, 292, 274, 263, 261, 269, 284, 304, 332, 360, 395, 413, 421, 418, 403, 382, 360, 339, 304, 276, 253, 229, 207, 164, 136, 105, 79, 53, 31, 18, 13, 19, 35, 58, 93};
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.first_fragment, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ConnectDotsView connectDotsView = (ConnectDotsView) view.findViewById(R.id.connect_dots_view);
connectDotsView.setOnCompleteListener(new ConnectDotsView.CompleteListener() {
@Override
public void onCompleteListener() {
Toast.makeText(getActivity(), "Completed", Toast.LENGTH_SHORT).show();
Log.e("Done", "true");
}
});
connectDotsView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
connectDotsView.getLocalVisibleRect(rect);
Log.e("Width", rect.width() + "");
Log.e("Height", rect.height() + "");
Log.e("left", rect.left + "");
Log.e("right", rect.right + "");
Log.e("top", rect.top + "");
Log.e("bottom", rect.bottom + "");
int scale = (int) getResources().getDisplayMetrics().density;
List<Point> points = new ArrayList<>();
for (int i = 0, j = 0; i < x.length && j < y.length; i++, j++) {
Point p = new Point(x[i] / scale + rect.left, y[j] / scale + rect.top);
points.add(p);
}
connectDotsView.setPoints(points);
}
});
}
@Override
public VerificationError verifyStep() {
return null;
}
@Override
public void onSelected() {
}
@Override
public void onError(@NonNull VerificationError error) {
}
}
自定义视图类:
package com.sagar.quizdemo;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
/**
* Displaying canvas with optional dots drawn on it. User can connect dots with
* straight lines. First dot can be connected with second dot, second with third
* etc.
*
* @author lecho
*/
public class ConnectDotsView extends View {
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private static final int TOUCH_TOLERANCE_DP = 24;
private static final int BACKGROUND = 0xFFDDDDDD;
// Points to be connected.
private List<Point> mPoints = new ArrayList<>();
private int mLastPointIndex = 0;
private int mTouchTolerance;
private boolean isPathStarted = false;
CompleteListener completeListener;
public ConnectDotsView(Context context) {
super(context);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
interface CompleteListener {
void onCompleteListener();
}
public void setOnCompleteListener(CompleteListener listener) {
completeListener = listener;
}
public ConnectDotsView(Context context, AttributeSet attrs) {
super(context, attrs);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
public ConnectDotsView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mCanvas = new Canvas();
mPath = new Path();
initPaint();
}
public void clear() {
mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
mBitmap.eraseColor(BACKGROUND);
mCanvas.setBitmap(mBitmap);
invalidate();
}
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
clear();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(BACKGROUND);
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawPath(mPath, mPaint);
// TODO remove if you don't want points to be visible.
for (Point point : mPoints) {
canvas.drawPoint(point.x, point.y, mPaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up(x, y);
invalidate();
break;
}
return true;
}
private void touch_start(float x, float y) {
if (checkPoint(x, y, mLastPointIndex)) {
mPath.reset();
// User starts from given point so path can be drawn.
isPathStarted = true;
} else {
// User starts move from point which does not belong to mPoints list
isPathStarted = false;
}
}
private void touch_move(float x, float y) {
if (isPathStarted) {
mPath.reset();
Point point = mPoints.get(mLastPointIndex);
mPath.moveTo(point.x, point.y);
if (checkPoint(x, y, mLastPointIndex + 1)) {
point = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(point.x, point.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
++mLastPointIndex;
} else {
int positionIndex = mLastPointIndex + 1;
if (positionIndex >= mPoints.size()) {
completeListener.onCompleteListener();
} else {
mPath.lineTo(x, y);
}
}
}
}
private void touch_up(float x, float y) {
mPath.reset();
if (checkPoint(x, y, mLastPointIndex + 1) && isPathStarted) {
// Move finished at valid point so I draw whole line.
// That's the start point of current line segment.
Point point = mPoints.get(mLastPointIndex);
mPath.moveTo(point.x, point.y);
// And that's the end point.
point = mPoints.get(mLastPointIndex + 1);
mPath.lineTo(point.x, point.y);
mCanvas.drawPath(mPath, mPaint);
mPath.reset();
// Increment point index.
++mLastPointIndex;
isPathStarted = false;
}
}
/**
* Checks if user touch point with some tolerance
*/
private boolean checkPoint(float x, float y, int pointIndex) {
if (pointIndex >= mPoints.size()) {
// All dots already connected.
return false;
}
Point point = mPoints.get(pointIndex);
if (x > (point.x - mTouchTolerance) && x < (point.x + mTouchTolerance)) {
if (y > (point.y - mTouchTolerance) && y < (point.y + mTouchTolerance)) {
return true;
}
}
return false;
}
/**
* Sets up paint attributes.
*/
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(12);
mTouchTolerance = dp2px(TOUCH_TOLERANCE_DP);
}
/**
* Converts dpi units to px
*
* @param dp
* @return
*/
private int dp2px(int dp) {
Resources r = getContext().getResources();
float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
return (int) px;
}
public void setPaint(Paint paint) {
this.mPaint = paint;
}
public Bitmap getBitmap() {
return mBitmap;
}
public List<Point> getPoints() {
return mPoints;
}
public void setPoints(List<Point> points) {
this.mPoints = points;
}
}
图片链接: https://i.stack.imgur.com/n67mq.png
请帮我解决这个问题。
答案 0 :(得分:1)
您可以使用以下计算在中心绘图,
connectDotsView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
// Fist find the min and max value for x axis
int minX = x[0];
int maxX = x[0];
for (int i = 1; i <= x.length - 1; i++) {
if (maxX < x[i]) {
maxX = x[i];
}
if (minX > x[i]) {
minX = x[i];
}
}
// Find min and max vlaue for Y axis
int minY = y[0];
int maxY = y[0];
for (int i = 1; i <= y.length - 1; i++) {
if (maxY < y[i]) {
maxY = y[i];
}
if (minY > y[i]) {
minY = y[i];
}
}
connectDotsView.getLocalVisibleRect(rect);
Log.e("Width", rect.width() + "");
Log.e("Height", rect.height() + "");
Log.e("left", rect.left + "");
Log.e("right", rect.right + "");
Log.e("top", rect.top + "");
Log.e("bottom", rect.bottom + "");
// Find the scale factor based on the view you allocated in the screen
float scaleX = ((float) ((float) rect.width() / (float) maxX));
float scaleY = ((float) ((float) rect.height() / (float) maxY));
final float scale;
// Take the lowest scale factor
if (scaleX > scaleY) {
scale = scaleY;
} else {
scale = scaleX;
}
// find the left and top
int left = (rect.width() - ((int) ((float) maxX * scale)) - ((int) ((float) minX * scale))) / 2;
int top = (rect.height() - ((int) ((float) maxY * scale)) - ((int) ((float) minY * scale))) / 2;
// base on the above calculation draw in a view
List<Point> points = new ArrayList<>();
for (int i = 0, j = 0; i < x.length && j < y.length; i++, j++) {
Point p = new Point(((int) ((float) x[i] * scale)) + left, (int) ((float) y[j] * scale) + top);
points.add(p);
}
connectDotsView.setPoints(points);
}
});
输出将是这样的,