2017-07-18 63 views
4

我在視圖上繪製了一組點,如下圖所示。如何重新定位不同屏幕分辨率的視圖上的點?

詳細說明:

我有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

請參閱最新的問題。 – XoXo

回答

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); 
     } 
    }); 

輸出會是這樣,

enter image description here

+0

精湛!它的工作完美。希望它不會改變其在不同屏幕分辨率下的位置。按照設備的屏幕分辨率運行,這會畫出來嗎? – XoXo

+0

不,它不會改變位置,因爲我的計算是基於視圖大小和你給出的點。 –