具有动态位置的布局

发布于 2024-09-18 17:36:31 字数 6114 浏览 6 评论 0原文

我的布局可能有点不寻常。结构如下:

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

XML 底部的我的 customRelativeLayout 也有一个 XML 布局:

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

我的 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);
    }
}

我想要做什么: 我希望能够更改我的 CustomRelativeLayout 的位置。应该是跟随我的触摸。它比 SurfaceView 小,应该随着我的触摸在上面“滑动”...

有两个问题:

  1. 绑定到 mLinearLayout(在 CustomRelativeLayout 中)的 onTouchListener 仅触发一次,并且仅针对 ACTION_DOWN。我只看到一次日志输出。
  2. 注释永远不会更改位置,也不会使用更改后的矩阵重新绘制...我在触摸发生后从未看到 onDraw 中声明的输出。

首先可能是因为 SurfaceView 还处理触摸事件。但我认为如果 CustomRelativeLayout 首先处理它,它应该可以工作。

一些想法?

编辑解决方案

感谢 Xil3,我能够移除遇到的墙...这是我的解决方案:

我的注释 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>

这是我的构造函数:

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;
        }
    });
}

我还发现了一个错误/功能/问题,这对我来说绝对是新的:当我删除注释根元素中的背景(当前是透明的)时,注释仅在我在内部 LinearLayout 中设置的 200dp 宽度/高度内可见。因此,它不是 fill_parent,而是 wrap_content,即使我将其设置为 fill_parent 也是如此。所以 layout_widthlayout_height 仅在设置背景时使用给定的 fill_parent...奇怪...

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

橘虞初梦 2024-09-25 17:36:31

问题是您在 onTouch 事件中返回 false - 因此,您基本上是在告诉它您对任何后续事件都不感兴趣。

将其更改为返回 true。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文