我认为可以递归地使用 getParent 直到找到代表要绘制空间的父级。我没有尝试这样做,因为它非常依赖于您使用的布局。如果您更改布局,您可能需要更改代码。
相反,在布局的顶层,我选择了 FrameLayout 并将我想要的布局作为它的子布局。作为第二个孩子,我放了一个“空”的视图,背景透明。FrameLayout 将所有子级显示在彼此之上。所以我的“空”视图显示在我想要的布局之上。例子:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:MyApp="http://schemas.android.com/apk/res/com.example.mockup"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
... stuff for my desired layout ...
</TableLayout>
<com.example.mockup.ActivityView
android:id="@+id/activity_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@null" />
</FrameLayout>
除了位置计算之外,代码非常简单。为了独立于布局,我发现最好将所有内容都转换为屏幕坐标;否则 getTop()、getLeft() 返回相对于直接父级的值,这可能与您计划绘制的空间不同。这是我在启动绘图的小部件中所做的。首先,您在活动中需要这个:
private ActivityView mActivityView ;
@Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// get "activity" view - this covers the whole activity space
mActivityView = (ActivityView)findViewById (R.id.activity_view);
// find the widget and give it the activity view
MyWidget widget = (MyWidget)findViewById (R.id.my_widget);
widget.setActivityView (mActivityView);
}
您将在小部件中需要它 - 启动绘图的那个:
public void setActivityView (ActivityView v)
{
mActivityView = v;
}
public void drawThing (float touchX, float touchY)
// touchX, touchY - location where user is touching, relative to "this" widget.
{
int[] locScreen = new int[2]; // x,y
getLocationOnScreen (locScreen);
int xScreen = locScreen[0] + touchX;
int yScreen = locScreen[1] + touchY;
mActivityView.drawThing (xScreen, yScreen);
}
最后,您需要在 ActivityView 中进行绘图
private int mXThing;
private int mYThing;
@Override
protected void onDraw (Canvas canvas)
{
super.onDraw (canvas);
... draw the "thing" using mXThing, mYThing ...
}
void drawThing (int xScreen, int yScreen)
{
// convert to view coords.
int[] loc = new int[2]; // x,y
getLocationOnScreen (loc);
mXThing = xScreen - loc[0];
mYThing = yScreen - loc[1];
invalidate();
}
我想还有其他方法可以做到这一点,也许更好。如果有人有建议,请随时发表评论。