Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
555 views
in Technique[技术] by (71.8m points)

android - Layout with dynamic position

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...

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...