Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/219.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用Zoomble RelativeLayout时,标签视图工作不正常_Android_Image Processing_Drag And Drop_Pinchzoom_Zooming - Fatal编程技术网

Android 使用Zoomble RelativeLayout时,标签视图工作不正常

Android 使用Zoomble RelativeLayout时,标签视图工作不正常,android,image-processing,drag-and-drop,pinchzoom,zooming,Android,Image Processing,Drag And Drop,Pinchzoom,Zooming,我想要的功能如下: 放大或缩小后,用户可以在图像的任何位置拖动、旋转、缩放标签(图像、文本) 为了实现这一点,我使用了可缩放的CreativeLayout和Sticker View,而不是仅缩放图像,而是缩放整个RelativeLayout,包括所有子视图(Sticker、image等) 现在的问题是,在我的RelativeLayout没有缩放之前,一切都正常。我可以将标签拖动到任何地方,但只要我缩放相对布局并尝试移动标签,它就会显示奇怪的行为 标签在放大后显示在正确的位置,但它的触摸位置似

我想要的功能如下:

  • 放大或缩小后,用户可以在图像的任何位置拖动、旋转、缩放标签(图像、文本)
  • 为了实现这一点,我使用了可缩放的CreativeLayout和Sticker View,而不是仅缩放图像,而是缩放整个RelativeLayout,包括所有子视图(Sticker、image等)
现在的问题是,在我的RelativeLayout没有缩放之前,一切都正常。我可以将标签拖动到任何地方,但只要我缩放相对布局并尝试移动标签,它就会显示奇怪的行为

标签在放大后显示在正确的位置,但它的触摸位置似乎正在改变,所以我无法在放大布局后拖动标签

我已经使用了标签库查看代码,缩放相关布局代码和布局如下

public class ZoomView extends RelativeLayout {

public ZoomView(final Context context) {
    super(context);
    //setOnTouchListener(touchListener);
}


public ZoomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    // setOnTouchListener(touchListener);
}

public ZoomView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    // setOnTouchListener(touchListener);
}

/**
 * Zooming view listener interface.
 *
 * @author karooolek
 */
public interface ZoomViewListener {

    void onZoomStarted(float zoom, float zoomx, float zoomy);

    void onZooming(float zoom, float zoomx, float zoomy);

    void onZoomEnded(float zoom, float zoomx, float zoomy);
}

// zooming
float zoom = 1.0f;
float maxZoom = 3.0f;
float smoothZoom = 1.0f;
float zoomX, zoomY;
float smoothZoomX, smoothZoomY;
private boolean scrolling; // NOPMD by karooolek on 29.06.11 11:45

// minimap variables
private boolean showMinimap = false;
private int miniMapColor = Color.BLACK;
private int miniMapHeight = -1;
private String miniMapCaption;
private float miniMapCaptionSize = 10.0f;
private int miniMapCaptionColor = Color.WHITE;

// touching variables
private long lastTapTime;
private float touchStartX, touchStartY;
private float touchLastX, touchLastY;
private float startd;
private boolean pinching;
private float lastd;
private float lastdx1, lastdy1;
private float lastdx2, lastdy2;

// drawing
private final Matrix m = new Matrix();
private final Paint p = new Paint();

// listener
ZoomViewListener listener;

private Bitmap ch;


public float getZoom() {
    return zoom;
}

public float getMaxZoom() {
    return maxZoom;
}

public void setMaxZoom(final float maxZoom) {
    if (maxZoom < 1.0f) {
        return;
    }

    this.maxZoom = maxZoom;
}

public void setMiniMapEnabled(final boolean showMiniMap) {
    this.showMinimap = showMiniMap;
}

public boolean isMiniMapEnabled() {
    return showMinimap;
}

public void setMiniMapHeight(final int miniMapHeight) {
    if (miniMapHeight < 0) {
        return;
    }
    this.miniMapHeight = miniMapHeight;
}

public int getMiniMapHeight() {
    return miniMapHeight;
}

public void setMiniMapColor(final int color) {
    miniMapColor = color;
}

public int getMiniMapColor() {
    return miniMapColor;
}

public String getMiniMapCaption() {
    return miniMapCaption;
}

public void setMiniMapCaption(final String miniMapCaption) {
    this.miniMapCaption = miniMapCaption;
}

public float getMiniMapCaptionSize() {
    return miniMapCaptionSize;
}

public void setMiniMapCaptionSize(final float size) {
    miniMapCaptionSize = size;
}

public int getMiniMapCaptionColor() {
    return miniMapCaptionColor;
}

public void setMiniMapCaptionColor(final int color) {
    miniMapCaptionColor = color;
}

public void zoomTo(final float zoom, final float x, final float y) {
    this.zoom = Math.min(zoom, maxZoom);
    zoomX = x;
    zoomY = y;
    smoothZoomTo(this.zoom, x, y);
}

public void smoothZoomTo(final float zoom, final float x, final float y) {
    smoothZoom = clamp(1.0f, zoom, maxZoom);
    smoothZoomX = x;
    smoothZoomY = y;
    if (listener != null) {
        listener.onZoomStarted(smoothZoom, x, y);
    }
}

public ZoomViewListener getListener() {
    return listener;
}

public void setListner(final ZoomViewListener listener) {
    this.listener = listener;
}

public float getZoomFocusX() {
    return zoomX * zoom;
}

public float getZoomFocusY() {
    return zoomY * zoom;
}

/* @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    return false;
}*/

/*@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {

    // single touch
    if (ev.getPointerCount() == 1) {
        processSingleTouchEvent(ev);
    }

    // // double touch
    if (ev.getPointerCount() == 2) {
        processDoubleTouchEvent(ev);
    }

    // redraw
    getRootView().invalidate();
    invalidate();
    return true;
}*/

OnTouchListener touchListener = new OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent ev) {
        // single touch
        if (ev.getPointerCount() == 1) {
            processSingleTouchEvent(ev);
        }
        // // double touch
        if (ev.getPointerCount() == 2) {
            processDoubleTouchEvent(ev);
        }
        // redraw
       /* getRootView().invalidate();
        invalidate();*/
        return true;
    }
};

public void onTouch(View v, MotionEvent ev) {
    if (ev.getPointerCount() == 1) {
        processSingleTouchEvent(ev);
    }
    // // double touch
    if (ev.getPointerCount() == 2) {
        processDoubleTouchEvent(ev);
    }
    // redraw
    getRootView().invalidate();
    invalidate();
}

private void processSingleTouchEvent(final MotionEvent ev) {

    final float x = ev.getX();
    final float y = ev.getY();

    final float w = miniMapHeight * (float) getWidth() / getHeight();
    final float h = miniMapHeight;
    final boolean touchingMiniMap = x >= 10.0f && x <= 10.0f + w && y >= 10.0f && y <= 10.0f + h;

    if (showMinimap && smoothZoom > 1.0f && touchingMiniMap) {
        processSingleTouchOnMinimap(ev);
    } else {
        processSingleTouchOutsideMinimap(ev);
    }
}

private void processSingleTouchOnMinimap(final MotionEvent ev) {
    final float x = ev.getX();
    final float y = ev.getY();

    final float w = miniMapHeight * (float) getWidth() / getHeight();
    final float h = miniMapHeight;
    final float zx = (x - 10.0f) / w * getWidth();
    final float zy = (y - 10.0f) / h * getHeight();
    smoothZoomTo(smoothZoom, zx, zy);
}

private void processSingleTouchOutsideMinimap(final MotionEvent ev) {
    final float x = ev.getX();
    final float y = ev.getY();
    float lx = x - touchStartX;
    float ly = y - touchStartY;
    final float l = (float) Math.hypot(lx, ly);
    float dx = x - touchLastX;
    float dy = y - touchLastY;
    touchLastX = x;
    touchLastY = y;

    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            touchStartX = x;
            touchStartY = y;
            touchLastX = x;
            touchLastY = y;
            dx = 0;
            dy = 0;
            lx = 0;
            ly = 0;
            scrolling = false;
            break;

        case MotionEvent.ACTION_MOVE:
            if (scrolling || (smoothZoom > 1.0f && l > 30.0f)) {
                if (!scrolling) {
                    scrolling = true;
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                    super.dispatchTouchEvent(ev);
                }
                smoothZoomX -= dx / zoom;
                smoothZoomY -= dy / zoom;
                return;
            }
            break;

        case MotionEvent.ACTION_OUTSIDE:
        case MotionEvent.ACTION_UP:

            // tap
            if (l < 30.0f) {
                // check double tap
                if (System.currentTimeMillis() - lastTapTime < 500) {
                    if (smoothZoom == 1.0f) {
                        smoothZoomTo(maxZoom, x, y);
                    } else {
                        smoothZoomTo(1.0f, getWidth() / 2.0f, getHeight() / 2.0f);
                    }
                    lastTapTime = 0;
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                    super.dispatchTouchEvent(ev);
                    return;
                }

                lastTapTime = System.currentTimeMillis();

                performClick();
            }
            break;

        default:
            break;
    }

    ev.setLocation(zoomX + (x - 0.5f * getWidth()) / zoom, zoomY + (y - 0.5f * getHeight()) / zoom);

    ev.getX();
    ev.getY();

    // super.dispatchTouchEvent(ev);
}

private void processDoubleTouchEvent(final MotionEvent ev) {
    final float x1 = ev.getX(0);
    final float dx1 = x1 - lastdx1;
    lastdx1 = x1;
    final float y1 = ev.getY(0);
    final float dy1 = y1 - lastdy1;
    lastdy1 = y1;
    final float x2 = ev.getX(1);
    final float dx2 = x2 - lastdx2;
    lastdx2 = x2;
    final float y2 = ev.getY(1);
    final float dy2 = y2 - lastdy2;
    lastdy2 = y2;

    // pointers distance
    final float d = (float) Math.hypot(x2 - x1, y2 - y1);
    final float dd = d - lastd;
    lastd = d;
    final float ld = Math.abs(d - startd);

    Math.atan2(y2 - y1, x2 - x1);
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startd = d;
            pinching = false;
            break;

        case MotionEvent.ACTION_MOVE:
            if (pinching || ld > 30.0f) {
                pinching = true;
                final float dxk = 0.5f * (dx1 + dx2);
                final float dyk = 0.5f * (dy1 + dy2);
                smoothZoomTo(Math.max(1.0f, zoom * d / (d - dd)), zoomX - dxk / zoom, zoomY - dyk / zoom);
            }
            break;

        case MotionEvent.ACTION_UP:
        default:
            pinching = false;
            break;
    }

    ev.setAction(MotionEvent.ACTION_CANCEL);
    //super.dispatchTouchEvent(ev);
}

private float clamp(final float min, final float value, final float max) {
    return Math.max(min, Math.min(value, max));
}

private float lerp(final float a, final float b, final float k) {
    return a + (b - a) * k;
}

private float bias(final float a, final float b, final float k) {
    return Math.abs(b - a) >= k ? a + k * Math.signum(b - a) : b;
}

@Override
protected void dispatchDraw(final Canvas canvas) {
    // do zoom
    zoom = lerp(bias(zoom, smoothZoom, 0.05f), smoothZoom, 0.2f);
    smoothZoomX = clamp(0.5f * getWidth() / smoothZoom, smoothZoomX, getWidth() - 0.5f * getWidth() / smoothZoom);
    smoothZoomY = clamp(0.5f * getHeight() / smoothZoom, smoothZoomY, getHeight() - 0.5f * getHeight() / smoothZoom);

    zoomX = lerp(bias(zoomX, smoothZoomX, 0.1f), smoothZoomX, 0.35f);
    zoomY = lerp(bias(zoomY, smoothZoomY, 0.1f), smoothZoomY, 0.35f);
    if (zoom != smoothZoom && listener != null) {
        listener.onZooming(zoom, zoomX, zoomY);
    }

    final boolean animating = Math.abs(zoom - smoothZoom) > 0.0000001f
            || Math.abs(zoomX - smoothZoomX) > 0.0000001f || Math.abs(zoomY - smoothZoomY) > 0.0000001f;

    // nothing to draw
    if (getChildCount() == 0) {
        return;
    }

    // prepare matrix
    m.setTranslate(0.5f * getWidth(), 0.5f * getHeight());
    m.preScale(zoom, zoom);
    m.preTranslate(-clamp(0.5f * getWidth() / zoom, zoomX, getWidth() - 0.5f * getWidth() / zoom),
            -clamp(0.5f * getHeight() / zoom, zoomY, getHeight() - 0.5f * getHeight() / zoom));

    // get view
    final View v = getChildAt(0);
    m.preTranslate(v.getLeft(), v.getTop());

    // get drawing cache if available
    if (animating && ch == null && isAnimationCacheEnabled()) {
        v.setDrawingCacheEnabled(true);
        ch = v.getDrawingCache();
    }

    // draw using cache while animating
    if (animating && isAnimationCacheEnabled() && ch != null) {
        p.setColor(0xffffffff);
        canvas.drawBitmap(ch, m, p);
    } else { // zoomed or cache unavailable
        ch = null;
        canvas.save();
        canvas.concat(m);
        v.draw(canvas);
        canvas.restore();
    }

    // draw minimap
    if (showMinimap) {
        if (miniMapHeight < 0) {
            miniMapHeight = getHeight() / 4;
        }

        canvas.translate(10.0f, 10.0f);

        p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
        final float w = miniMapHeight * (float) getWidth() / getHeight();
        final float h = miniMapHeight;
        canvas.drawRect(0.0f, 0.0f, w, h, p);

        if (miniMapCaption != null && miniMapCaption.length() > 0) {
            p.setTextSize(miniMapCaptionSize);
            p.setColor(miniMapCaptionColor);
            p.setAntiAlias(true);
            canvas.drawText(miniMapCaption, 10.0f, 10.0f + miniMapCaptionSize, p);
            p.setAntiAlias(false);
        }

        p.setColor(0x80000000 | 0x00ffffff & miniMapColor);
        final float dx = w * zoomX / getWidth();
        final float dy = h * zoomY / getHeight();
        canvas.drawRect(dx - 0.5f * w / zoom, dy - 0.5f * h / zoom, dx + 0.5f * w / zoom, dy + 0.5f * h / zoom, p);

        canvas.translate(-10.0f, -10.0f);
    }

    // redraw
    // if (animating) {
    getRootView().invalidate();
    invalidate();
    // }
}
}
公共类ZoomView扩展了RelativeLayout{
公共ZoomView(最终上下文){
超级(上下文);
//setOnTouchListener(touchListener);
}
公共ZoomView(上下文、属性集属性){
超级(上下文,attrs);
//setOnTouchListener(touchListener);
}
公共ZoomView(上下文、属性集属性、int defStyleAttr){
super(上下文、attrs、defStyleAttr);
//setOnTouchListener(touchListener);
}
/**
*缩放视图侦听器界面。
*
*@作者卡鲁奥利克
*/
公共接口ZoomViewListener{
void onZoomStarted(浮动缩放、浮动缩放、浮动缩放);
无效缩放(浮动缩放、浮动缩放、浮动缩放);
void onzoommended(浮动缩放、浮动缩放、浮动缩放);
}
//缩放
浮动缩放=1.0f;
float maxZoom=3.0f;
浮动平滑缩放=1.0f;
浮动zoomX,缩放;
浮动smoothZoomX、smoothZoomY;
私有布尔滚动;//NOPMD由karooolek于29.06.11 11:45
//小地图变量
私有布尔showMinimap=false;
private int miniMapColor=Color.BLACK;
私有整数最小值=-1;
私有字符串最小化;
私有浮动最小apcaptionSize=10.0f;
private int minimappationcolor=Color.WHITE;
//接触变量
私人长时间;
私人浮动touchStartX,touchStartY;
私人浮动touchLastX,touchLastY;
私人浮动标准;
私有布尔pinching;
私人浮动lastd;
私人浮动lastdx1,lastdy1;
私人浮动lastdx2,lastdy2;
//绘图
私有最终矩阵m=新矩阵();
专用最终油漆p=新油漆();
//听众
ZoomViewListener侦听器;
私家车;
公共浮点getZoom(){
返回缩放;
}
公共浮点getMaxZoom(){
返回最大缩放;
}
公共void setMaxZoom(最终浮点maxZoom){
如果(最大缩放<1.0f){
返回;
}
this.maxZoom=maxZoom;
}
公共void setMiniMapEnabled(最终布尔值showMiniMap){
this.showMinimap=showMinimap;
}
公共布尔值isMiniMapEnabled(){
返回小地图;
}
公共无效设置最小值(最终整数最小值){
如果(最小重量<0){
返回;
}
this.minimaphere=最小重量;
}
public int getminimaphight(){
返回微量计;
}
公共无效设置最小颜色(最终内部颜色){
最小颜色=颜色;
}
public int getminimacpolor(){
返回最小颜色;
}
公共字符串getMiniMapCaption(){
返回最小值;
}
public void setminimacaption(最终字符串minimacaption){
this.minimappation=minimappation;
}
公共浮点getMiniMapCaptionSize(){
返回最小apcaptionsize;
}
公共void setMiniMapCaptionSize(最终浮点大小){
miniMapCaptionSize=大小;
}
public int getminimappationcolor(){
返回最小颜色;
}
公共无效设置MinimapCaptionColor(最终内部颜色){
最小颜色=颜色;
}
公共空心缩放(最终浮动缩放、最终浮动x、最终浮动y){
this.zoom=Math.min(zoom,maxZoom);
zoomX=x;
zoomY=y;
smoothZoomTo(this.zoom,x,y);
}
公共空心smoothZoomTo(最终浮点缩放、最终浮点x、最终浮点y){
平滑缩放=钳制(1.0f,缩放,最大缩放);
smoothZoomX=x;
smoothZoomY=y;
if(侦听器!=null){
onZoomStarted(平滑缩放,x,y);
}
}
公共ZoomViewListener getListener(){
返回侦听器;
}
public void setListner(最终ZoomViewListener侦听器){
this.listener=listener;
}
公共浮点getZoomFocusX(){
返回zoomX*zoom;
}
公共浮点getZoomFocusY(){
返回zoomY*zoom;
}
/*@覆盖
公共布尔值onInterceptTouchEvent(MotionEvent ev){
返回false;
}*/
/*@凌驾
公共布尔dispatchTouchEvent(最终运动事件ev){
//单触式
if(ev.getPointerCount()==1){
processSingleTouchEvent(ev);
}
////双重接触
if(ev.getPointerCount()==2){
processDoubleTouchEvent(ev);
}
//重画
getRootView().invalidate();
使无效();
返回true;
}*/
OnTouchListener touchListener=新建OnTouchListener(){
@凌驾
公共布尔onTouch(视图v、运动事件ev){
//单触式
if(ev.getPointerCount()==1){
processSingleTouchEvent(ev);
}
////双重接触
if(ev.getPointerCount()==2){
processDoubleTouchEvent(ev);
}
//重画
/*getRootView().invalidate();
使无效()*/
返回true;
}
};
公共无效onTouch(视图v、运动事件ev){
if(ev.getPointerCount()==1){
processSingleTouchEvent(ev);
}
////双重接触
if(ev.getPointerCount()==2){
processDoubleTouchEvent(ev);
}
//重画
getRootView().invalidate();
使无效();
}
私有void processSingleTouchEvent(最终MotionEvent ev){
最终浮点数x=ev.getX();
最终浮动y=ev.getY();
最终浮动w=最小重量*(浮动)getWidth()/getHeight();
最终浮球h=最小浮球;
最终布尔值touchingMiniMap=x>=10.0f&&x=10.0f&&y 1.0f&&touchingMiniMap){
processSingleTouchOnMinimap(ev);
}否则{
处理单点接触外血脂(ev);
   <com.nkdroid.stickerview.widgets.ZoomView
    android:id="@+id/zoomableLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/rlUndoRedo"
    android:layout_centerInParent="true">

    <FrameLayout
        android:id="@+id/canvasView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".ui.activities.MainActivity"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true">

        <com.nkdroid.stickerview.widgets.DrawingView
            android:id="@+id/fingerLine"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:adjustViewBounds="true"
            android:contentDescription="@string/app_name"
            android:scaleType="centerCrop"
            android:src="@drawable/image" />

    </FrameLayout>

</com.nkdroid.stickerview.widgets.ZoomView>