Android Zoomable无止境戒指

时间:2018-07-27 08:09:10

标签: android android-animation android-canvas android-relativelayout

我正在尝试创建一个无尽的可缩放环,像这样-

enter image description here

每当用户捏放大时,就会在中心创建一个新的小圆圈,而外圆圈会变大。我正在使用pinch zoom in relative layout来创建以下效果,但无法正确实现。我已经为此创建了一个仓库,让我知道您是否可以提供帮助 https://github.com/rohankandwal/zoomable-growing-circles

更新:- 在提到的stackoverflow答案上更改了dispatchDraw方法-

protected void dispatchDraw(Canvas canvas) {
    Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    myPaint.setStyle(Paint.Style.STROKE);
    int strokeWidth = 4;  // or whatever
    myPaint.setStrokeWidth(strokeWidth);
    myPaint.setColor(0xffff0000);   //color.RED
    float radius = (float) (0.5 * (width + height) * 2.5);
    for (int i = 1; i <= 51; i=i+10) {
      canvas.drawCircle(canvas.getWidth() / 2, canvas.getWidth() / 2, (radius) + mScaleFactor + i,
        myPaint);
    }
    canvas.save();
    super.dispatchDraw(canvas);
    canvas.restore();
  }

此代码允许圈子扩大-

没有捏缩放的原始图像

Image without zoom

缩放时的图像

Image with zoom

如您所见,缩放有效,但不知道在特定级别缩放时如何创建新的圆圈。

2 个答案:

答案 0 :(得分:3)

如果我正确理解了您想要的内容,则代码中没有太多更改

OnPinchListener中:

public boolean onScale(ScaleGestureDetector detector) {
    // 1 : no zoom
    final float zoomLevel = detector.getCurrentSpan() / startingSpan;
    zoomableRadarLayout.scale(zoomLevel, startFocusX, startFocusY);
    return true;
}

ZoomableRadarLayout中的

// current pinch
private float mScaleFactor = 1;
// previous pinches
private float mAccumulatedScaleFactor = 1;


protected void dispatchDraw(Canvas canvas) {
    ...

    float radius = (float) (0.5 * (width + height) * 2.5);

    // space between circles
    int step = 10;
    // radius of the outer circle
    int outerRadius = (int) (radius * mScaleFactor * mAccumulatedScaleFactor);
    // radius of the inner circle
    int innerRadius = 0;

    for (int i = outerRadius; i >= innerRadius; i = i - step) {
        canvas.drawCircle(canvas.getWidth() / 2, canvas.getWidth() / 2, i, myPaint);
    }

    ...

}

public void restore() {
    // add the ending pinch to the previous ones
    mAccumulatedScaleFactor = mAccumulatedScaleFactor * mScaleFactor;
    mScaleFactor = 1;
    this.invalidate();
}

如果可能的话,建议避免在绘图时创建诸如Paint之类的绘图对象。例如将创建内容放在某种init方法中。

答案 1 :(得分:1)

您可以使用这种方法:计算内圆的半径(最小半径),然后绘制圆并增大半径,而圆在屏幕上可见(最大半径不大于从屏幕中心到其一个角的距离) )。尝试使用ScaleGestureDetector的自定义视图:

public class ZoomableRingView extends View {

    private Paint mPaint;
    private ScaleGestureDetector mScaleDetector;
    private float mDeltaRadius = 0;
    private final float mBaseRadius = 50;
    private float mPinchBaseRadius = mBaseRadius;
    private float mMinRadius = mBaseRadius;

    public ZoomableRingView(Context context) {
        super(context);
        init(context);
    }

    public ZoomableRingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ZoomableRingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public ZoomableRingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    @Override
    public void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        canvas.save();
        drawCircles(canvas);
        canvas.restore();
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        mScaleDetector.onTouchEvent(ev);
        return true;
    }

    private void init(Context context) {
        setWillNotDraw(false);

        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(5);

        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    private void drawCircles(Canvas canvas) {
        int canvasWidth = canvas.getWidth();
        int canvasHeight = canvas.getHeight();

        int centerX = canvasWidth / 2;
        int centerY = canvasHeight / 2;

        float maxRadius = (float) Math.sqrt(centerX * centerX + centerY * centerY);
        int nCircles = (int) Math.ceil(maxRadius / mBaseRadius) + 1;

        // calculate radius change
        mMinRadius = mPinchBaseRadius + mDeltaRadius / 2;

        // bring radius to [0..2 * mBaseRadius] interval
        while (mMinRadius < 1f) {
            mMinRadius += 2 * mBaseRadius;
        }
        while (mMinRadius > 2 * mBaseRadius) {
            mMinRadius -= 2 * mBaseRadius;
        }

        // draw circles from min to max
        float radius = mMinRadius;
        for (int ixCircle = 0; ixCircle < nCircles; ixCircle++) {
            canvas.drawCircle(centerX, centerY, radius, mPaint);
            radius += 2 * mBaseRadius;
        }
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        float startingSpan;

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            mPinchBaseRadius = mMinRadius;
            startingSpan = detector.getCurrentSpan();
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            mDeltaRadius = detector.getCurrentSpan() - startingSpan;
            invalidate();
            return true;
        }
    }
}

您拥有该自定义视图的activity.xml可能像这样:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:id="@+id/layout_channel1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

    <{YOUR_PACKAGE_NAME}.ZoomableRingView
        android:id="@+id/zoomablering_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

您应该得到类似的东西:

Infinite ring zoom