Layout with dynamic position

2019-01-28 02:36发布

问题:

I have a layout which might be a bit unusual. The structure is the following:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <org.CustomSurfaceView
        android:id="@+id/page_flip"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginBottom="20dip" />

    <org.customRelativeLayout
        android:id="@+id/note"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:visibility="gone" />
</FrameLayout>

My customRelativeLayout at the bottom of the XML has a XML layout too:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:background="@drawable/my_background"
    android:id="@+id/note_layout">
    <TextView android:id="@+id/note"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:singleLine="false"
        android:layout_margin="5dp"
        android:textColor="#000000" />
</LinearLayout>

My CustomRelativeLayout:

public class CustomRelativeLayout extends RelativeLayout implements OverlayView {

    private TextView mNoteText;
    private LinearLayout mLinearLayout;
    public int mX = 0;
    public int mY = 0;
    public boolean mShow;

    public CustomRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        li.inflate(R.layout.note, this);
        mNoteText = (TextView) findViewById(R.id.note);
        mLinearLayout = (LinearLayout) findViewById(R.id.note_layout);

        mLinearLayout.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("touched");
                mX = (int) event.getX() - 100;
                mY = (int) event.getY() - 100;
                invalidate();
                return false;
            }
        });
    }

    @Override
    public void hide() {
        mShow = false;
        setVisibility(View.GONE);
    }

    @Override
    public boolean isVisible() {
        return isVisible();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.e("Drawing the postit");
        Matrix matrix = new Matrix();
        matrix.postTranslate(mX, mY);
        canvas.setMatrix(matrix);
        super.onDraw(canvas);
    }

    @Override
    public void setContent(Object content) {
        if (content != null && content instanceof Content) {
            Content noteContent = (Content) content;
            if (noteContent.getText() != null) {
                mNoteText.setText(noteContent.getText());
            } else {
                mNoteText.setText("");
            }
        }
        mNoteText.invalidate();
        mLinearLayout.invalidate();
    }

    @Override
    public void show() {
        mShow = true;
        setVisibility(View.VISIBLE);
    }
}

What I want to do: I want to be able to change the position of my CustomRelativeLayout. It should be follow my touch. Its smaller than the SurfaceView and should "slide" above following my touch...

There are two problems:

  1. The onTouchListener bind to mLinearLayout (in CustomRelativeLayout) is only triggered once and only for ACTION_DOWN. I see the log output only once
  2. The note never changes the position, it is never redrawn with the changed matrix... I see the output stated in onDraw never after the touch happened.

First might be because the SurfaceView also handles touch events. But I thought if the CustomRelativeLayout handles it first, it should work.

Some ideas?

Edit for solution

Thanks to Xil3 I was able to remove the wall I was run into... here is my solution:

my note xml:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/transparent">
    <LinearLayout android:layout_width="200dp"
        android:layout_height="200dp"
        android:background="@drawable/postit"
        android:id="@+id/textnote_layout">
        <TextView android:id="@+id/textnote_content"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:singleLine="false"
            android:layout_margin="5dp"
            android:textColor="#000000" />
    </LinearLayout>
</LinearLayout>

And here is my constructor:

public TextNoteOverlay(Context context, AttributeSet attrs) {
    super(context, attrs);

    LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    li.inflate(R.layout.textnote, this);
    mNoteText = (TextView) findViewById(R.id.textnote_content);
    mLinearLayout = (LinearLayout) findViewById(R.id.textnote_layout);

    setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            mLinearLayout.getHitRect(mNoteRect);
            if (mNoteRect.contains((int) event.getX(), (int) event.getY())) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    mStartX = (int) event.getX() - mLinearLayout.getLeft();
                    mStartY = (int) event.getY() - mLinearLayout.getTop();
                    return true;
                }
                mX = (int) event.getX() - mStartX;
                mY = (int) event.getY() - mStartY;
                mLinearLayout.layout(mX, mY, mX + mLinearLayout.getWidth(), mY + mLinearLayout.getHeight());
                return true;
            }
            return false;
        }
    });
}

I also found a bug/feature/issue, which is absolutely new for me: When I remove the background in my note root element (which is currently transparent) the note is only visible within the 200dp width/height I have set in the inner LinearLayout. So its not fill_parent, its wrap_content even as I set it to fill_parent. So layout_width and layout_height only use the given fill_parent when a background is set... weired...

回答1:

The problem is that you're returning false in the onTouch event - so, you're basically telling it that you're not interested in any subsequent events.

Change that to return true.