【问题标题】:Android Zoomable endless ringsAndroid 可缩放无限环
【发布时间】:2019-01-04 07:42:07
【问题描述】:

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

每当用户捏合缩放时,都会在中心创建新的小圆圈,并且外圈会变大。我正在使用pinch zoom in relative layout 创建以下效果,但无法正确实现。我为此创建了一个 repo,如果您可以提供帮助,请告诉我 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();
  }

此代码允许圈子增长 -

没有捏缩放的原始图像

捏缩放时的图像

如您所见,缩放工作正常,但不知道如何在缩放到特定级别时创建新圆圈。

【问题讨论】:

  • 投反对票有什么原因吗?

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


【解决方案1】:

如果我正确理解你想要什么,那么你的代码没有太大变化

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 方法中。

【讨论】:

  • 这只是您可能看到的粗略代码,因此我没有添加编码标准或改进。该代码看起来非常接近我想要的唯一问题,即缩放不能正常工作。让我知道您是否可以提供帮助。我自己也在尝试。
  • 我的意思是缩放客体,它​​不能正确缩放
  • 现在看起来好多了,dispatchDraw 事件更简单
  • 几乎完美,现在,唯一的问题是,每当我们再次开始捏缩放时,圆圈会变小然后动画。
  • 我不确定我是否理解,您的意思是您希望在手势完成后圆圈保持较大,这样您就可以开始新的捏合以进一步放大?
【解决方案2】:

您可以使用这种方法:计算内圆的半径(最小半径),然后绘制圆并增加半径,而圆可以在屏幕上可见(最大半径不大于从屏幕中心到其角之一的距离)。用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>

你应该得到类似的东西:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 2016-12-15
    相关资源
    最近更新 更多