问题
Here is what I would like my ScrollView to look like:
- The maximum size is defined with the layout_weight (so that other items below the ScrollView can be displayed properly)
- If the content is smaller than that maximum size, then it just behaves as with
layout_height="wrap_content"
Here is what I currently have:
<ScrollView
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:measureAllChildren="true"
android:fillViewport="false"
>
I don't think the measureAllChildren
really does anything at all...
If I add android:layout_weight
, the size will always be what I would like the maximum to be. Without it, it just extends more than it should...
I don't mind extending the ScrollView class to change the behavior of onMeasure if I need to...?
PS: If that makes a differences, I am trying to get this working from Froyo onward.
回答1:
I ended up writing my own class, extending ScrollView
Since you ask...here is the code. Probably not the cleanest but it does what I want.
Note that it expects the layout_weight to be set when the view is created and you should not set the weigthSum in the parent LinearLayout or you'll get funny things (since the weight of this one changes from the original value to 0 depending on the size of the content of the ScrollView)
First, in the layout file, the view is declared like this:
<com.matthieu.widget.ShrinkingScrollView
android:id="@+id/scroll"
android:scrollbars="vertical"
android:layout_height="0dp"
android:layout_width="fill_parent"
android:layout_weight="4"
android:background="#cc0000"
>
<TextView
android:id="@+id/in_scroll_view"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:background="#0000bb"
/>
</com.matthieu.widget.ShrinkingScrollView>
Then the code for the widget:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
import android.widget.ScrollView;
public class ShrinkingScrollView extends ScrollView {
private float original_weight=-1;
public ShrinkingScrollView(Context context) {
super(context);
}
public ShrinkingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ShrinkingScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) getLayoutParams();
float previous_weight = params.weight;
if (original_weight == -1)
original_weight = params.weight;
if ((getChildCount()>0) && (getVisibility()!=GONE)) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED));
int overall_height = getChildAt(0).getMeasuredHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getMeasuredHeight() >= overall_height) {
if (previous_weight != 0) {
params.weight=0;
params.height = overall_height;
setLayoutParams(params);
post(new Runnable() {
public void run() {
requestLayout();
}
});
}
setMeasuredDimension(getMeasuredWidth(),overall_height);
}
else if (previous_weight == 0) {
params.weight = original_weight;
params.height = 0;
setLayoutParams(params);
post(new Runnable() {
public void run() {
requestLayout();
}
});
}
}
else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
回答2:
If I understand your requirement correctly, the way I have done something like this is to place the scrollview along with anything else you want to display below it into a Relative layout. Then, in your layout file place the item on the bottom of the screen in the file first (with android:layout_alignParentBottom="true"), then put the scroll view and place it above the first item using something like:android:layout_above="@id/firstItem". Like this in which I put an image view on the bottom with a scroll view above it taking the remaining space:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/searchByNameScreen"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:layout_marginTop="1dip"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ImageView
android:id="@+id/bottomImage"
android:layout_width="fill_parent"
android:layout_height="75dip"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:paddingBottom="15dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
android:paddingTop="7dip"
android:scaleType="fitXY"
android:src="@drawable/android_450x50_moreinfo" />
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ScrollView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/bottomImage"
android:layout_marginBottom="3dip"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="1dip"
android:scrollbars="none" >
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/aboutCopyLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/aboutTopLayer"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:background="@drawable/rounded_background"
android:gravity="center"
android:padding="5dip" >
<!-- android:background="@drawable/rounded_background" -->
<TextView
android:id="@+id/aboutCopyText"
style="@style/ResortNameExtraLine"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:text="@string/aboutCopy" />
</LinearLayout>
</ScrollView>
</RelativeLayout>
回答3:
Here another solution using sizes instead of weights. I've extended ScrollView and added code to implement this feature:
https://gist.github.com/JMPergar/439aaa3249fa184c7c0c
I hope that be useful.
回答4:
JMpergar answer seems right but its not worked until I changed the onMeasure method like below.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try {
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (maxHeight != WITHOUT_MAX_HEIGHT_VALUE
&& heightSize > maxHeight) {
heightSize = maxHeight;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
getLayoutParams().height = heightSize;
} else {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.AT_MOST);
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec)
, getDefaultSize(this.getSuggestedMinimumHeight(), heightMeasureSpec));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
来源:https://stackoverflow.com/questions/9457194/android-scrollview-layout-wrap-content-maximum-size