问题
I have a complicated LinearLayout
(vertical) with a FrameLayout
above some other stuff (a TextView
and an EditText
box). The FrameLayout
contains two things: a) a map and b) a ScrollView
containing a semi-transparent LinearLayout
that 'overlays' the map. The ScrollView is initially GONE
, but I render it visible programmatically. I also programmatically add Views into the LinearLayout
embedded in the ScrollView
.
The FrameLayout dimensions are set using onMeasure()
so that the height and width are equal. This make the FrameLayout
take up the top portion of the device screen while the TextView
and EditText
fit below.
public static class MyFrameLayout extends FrameLayout {
public FrameLayoutWithMap(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
setMeasuredDimension(size, size);
}
}
Everything actually works great in the beginning. However, when I add enough Views to the LinearLayout
embedded in the ScrollView
the ScrollView will eventually extend behind the TextView
below the FrameLayout
. In other words, the ScrollView overflows its FrameLayout
parent, the bottom of which is then hidden. As I continue to add Views to the LinearLayout
embedded in the ScrollView
the ScrollView
will eventually start scrolling. It appears as though this happens once the ScrollView
is the height of the device screen.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activityRoot"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#323232"
tools:context=".MainActivity" >
<FrameLayout
class="com.myapp.main.MyFrameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#070707" >
<com.myapp.main.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ScrollView
android:id="@+id/overlayScrollView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_gravity="left"
android:scrollbars="vertical"
android:fillViewport="false"
android:visibility="gone" >
<LinearLayout
android:id="@+id/overlayLinearLayout"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:padding="1dp"
android:background="#AA000000" >
</LinearLayout>
</ScrollView>
</FrameLayout>
<TextView
android:id="@+id/tvMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="left"
android:textColor="#FFFFFF"
android:textSize="14sp" />
<EditText android:id="@+id/entry"
android:background="@drawable/entry_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lines="1"
android:singleLine="true"
android:textSize="16sp"
android:textColor="#ffffff"
android:hint="@string/entry" />
</LinearLayout>
What I would like to happen is for the ScrollView
to start scrolling as soon as it's the height of its FrameLayout
parent. Put another way, I'd like for the ScrollView
to remain contained within its FrameLayout
parent.
Any idea what I'm doing wrong here?
回答1:
Update:
The new ConstraintLayout library gives you fine-grained control of how your views are sized in relation to the parent and to other views. It also supports aspect ratios, so you can (for instance) force a view to always be square.
Original response:
The problem is how you are measuring your special FrameLayout. When you call super.onMeasure()
, this view and all of its children will measure themselves according to the measure specs given. After that, you constrain the dimensions of this view, but none of its children are aware of this; only this view and its parent are aware of this. Its children have measured themselves thinking the size of this view is not constrained by your extra call to setMeasuredDimension()
.
Calling super.onMeasure()
again will force its children to measure themselves again, thereby informing them of the new size.
@Override
public void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
int spec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(spec, spec);
}
Note this will cause this view and all its children to measure twice as many times with each measure pass, so it might not be the most performant approach, but it will accomplish what you want.
来源:https://stackoverflow.com/questions/37338053/scrollview-overflowing-its-framelayout-parent