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.
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);
}
}
}
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>
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.
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);
}
}
you can just wrap your ScrollView into another ConstraintLayout, then constrain the height (the line app:layout_constrainedHeight="true"):
<!-- another constraint layout to keep ScrollView shrinking -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
Related
I've only included one direct child in the scroll view , and i've added the below codes in the java files. When i remove the Utility method the listview appear fully, but doesnt work as a scrollview
ScrollView sv_fragment_globe;
sv_fragment_globe = (ScrollView)rowView.findViewById(R.id.sv_fragment_globe);
sv_fragment_globe.smoothScrollTo(0,0);
Utility.setListViewHeightBasedOnChildren(holder.lv_globe);
<ScrollView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/sv_fragment_globe"
android:fillViewport="true"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:orientation="vertical"
>
<ImageView
android:layout_width="fill_parent"
android:layout_height="200dp"
android:src="#drawable/home_hospital1"
android:id="#+id/iv_vp_globe"
android:scaleType="fitXY"
/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/lv_globe"
>
</ListView>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
If you have more than two scrolling views inside any Layout, then the parent scrolling view will only scrolls. Follow the steps below to allows the child's scrolling elements to scroll.
Step 1:
Create a custom ListView.
public class ExpandableHeightListView extends ListView
{
boolean expanded = false;
public ExpandableHeightListView(Context context)
{
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,int defStyle)
{
super(context, attrs, defStyle);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// HACK! TAKE THAT ANDROID!
if (isExpanded())
{
// Calculate entire height by providing a very large height hint.
// But do not use the highest 2 bits of this integer; those are
// reserved for the MeasureSpec mode.
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
Step 2: Add the line below after initializing the Listview object.
lv_selected_time_zone.setExpanded(true);
Try this
<android.support.v4.widget.SwipeRefreshLayout
android:id="#+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="1"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="#android:drawable/home_hospital"
android:id="#+id/iv_vp_globe"
android:scaleType="fitXY"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/lv_globe"
android:layout_weight="1"
>
</ListView>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
Here I uses view and there code as per given below.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TableRow
android:id="#+id/tab_stone_info"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginTop="1dp"
android:background="#color/styleBreakTabColor"
android:weightSum="9">
<TextView
android:id="#+id/stone_Type"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Type"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Shape"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Shape"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Qlty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Quality"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Grade"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Grade"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Qty"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Qty"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Wt"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Wt"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_MMSize"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/MMSize"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_Setting"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/Setting"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
<TextView
android:id="#+id/stone_SettMode"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/cell_shape"
android:gravity="center"
android:text="#string/SettingMode"
android:textColor="#color/txtStyleBreakup"
android:textSize="12sp" />
</TableRow>
<RelativeLayout
android:id="#+id/layout_tab_stone_info_value"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.mindtech.ExpandableHeightListView
android:id="#+id/listviewstone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="#00000000"
android:gravity="center"
android:horizontalSpacing="2dp"
android:isScrollContainer="false"
android:stretchMode="columnWidth"
android:verticalSpacing="20dp"
/>
</RelativeLayout>
</LinearLayout>
And I uses epandablelistview as below class.
public class ExpandableHeightListView extends ListView
{
boolean expanded = false;
public ExpandableHeightListView(Context context, AttributeSet attrs,
int defStyle)
{
super(context, attrs, defStyle);
}
public ExpandableHeightListView(Context context)
{
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public boolean isExpanded()
{
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
// int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
// MeasureSpec.AT_MOST);
//
// super.onMeasure(widthMeasureSpec, expandSpec);
// int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
// Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
// super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
// ViewGroup.LayoutParams params = getLayoutParams();
// params.height = getMeasuredHeight();
if (isExpanded())
{
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded)
{
this.expanded = expanded;
}
}
I refer this question but did not get correct.
Grid of images inside ScrollView
Gridview height gets cut
The main problem occur when first row height is not biger than second or other. if all row content length are same then no issues.
It looks like you are getting the LayoutParams for your ListView, modifying the height parameter, but you are never calling setLayoutParams to tell the view to use the modified height. Try this:
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
//Add this line
setLayoutParams(params);
}
Also, I've ran into problems in the past with the onMeasure() method, not everything is measured when the framework calls that method. You might try a ViewTreeObserver, where you can register a listener to be notified when the full view is laid out, like this:
final LinearLayout layout = (LinearLayout) findViewById(R.id.layout_id);
ViewTreeObserver vto;
if (layout != null) {
vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//Modify your LayoutParams here
}
});
}
If there's only one child, then it's better to use ExpandableListView or RecyclerView with different layouts. Here is a complete and very good tutorial on using ExpandableListView.
While using ListView, it always adds height which is a bit less than the original one (or may be there's another case, but I don't know why. If someone knows, than kindly correct me). So you have to add some dp's height manually at the end.
I've done it by overriding onDraw method. Below is how I did it.
#Override
protected void onDraw(Canvas canvas) {
params = getLayoutParams();
if (getCount() != old_count) {
old_count = getCount();
params.height = getCount() * (old_count > 0 ? getChildAt(0).getHeight()+5 : 0);
//I've added 5 pixels with each item to get proper height, you can alter it as per your need
setLayoutParams(params);
}
super.onDraw(canvas);
}
You are modifying the height, but you are not passing it to the view.
Use this method, setLayoutParams(params);
I am trying to use a viewpager inside a dialog fragment (a SherlockDialogFragment actually). Every page consists of a text view with a left drawable. The problem i am facing is that the dialog size is 'wrong'. The width is too little, the height too much (it extends from top to bottom). For the width, i have "solved" this problem forcing its minimum width to be 70% of the screen width (via code, in the onCreateView() method of the dialog fragment). For the height, i don't know how to fix it. There is a button down there, but it can't be seen:
The viewpager is working (i can swipe the three pages i have setup). This is the dialog fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/dlg_bkg"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="TITLE"
android:textStyle="bold"
android:maxLines="1"
android:drawableLeft="#drawable/icon"
android:drawablePadding="8dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
<View
android:layout_width="fill_parent"
android:layout_height="2px"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/lineseparator"
android:visibility="visible" />
<android.support.v4.view.ViewPager
android:id="#+id/welcome_dlg_pager"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</android.support.v4.view.ViewPager>
<View
android:layout_width="fill_parent"
android:layout_height="2px"
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:background="#drawable/lineseparator"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="#+id/close_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="?selectableItemBackground"
android:minHeight="40dp"
android:text="Close"
android:textColor="#android:color/white" />
</LinearLayout>
</LinearLayout>
This is the example page layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/welcome_dlg_page1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Page 1 - ekrjgwoirhfwiorht2iu3hr2984hr893rhg3hff2jif283hr29837rh283eh23r23r2r23rwrgioehrg803"
android:drawableLeft="#drawable/img1"
android:drawablePadding="8dp"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
Why the dialog height is too much? How can i fix it?
I also had the same issue. I also wanted the height as per the viewpager's current item so I followed the following steps.
First of all, You need to override the onMeasure method of the viewpager. as explained here.
public class WrapContentViewPager extends ViewPager {
public WrapContentViewPager(#NonNull Context context) {
super(context);
}
public WrapContentViewPager(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
View child = getChildAt(getCurrentItem());
if (child != null) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
After that, Add PageChangeListener so that we can remeasure the viewpager's height every time when the viewpager item has been changed. We will add a initPageChangeListener() method and call it in the constructor.
public WrapContentViewPager(#NonNull Context context) {
super(context);
initPageChangeListener();
}
public WrapContentViewPager(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
initPageChangeListener();
}
private void initPageChangeListener() {
addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
requestLayout();
}
});
}
Now, I had the issue when the viewpager adapter has more than 3 items, So I added following lines in onMeasure(). as explained in this answer.
if (getAdapter() != null)
setOffscreenPageLimit(getAdapter().getCount());
And, everything works perfectly.
you have to overide the onstart method and set the height and width if dialouge fragment their,like
#Override
public void onStart(){
super.onStart();
if (getDialog() == null)
return;
int dialogWidth = ... // assign width here
int dialogHeight = ... // assign height here
getDialog().getWindow().setLayout(dialogWidth, dialogHeight);
}
Answer here:
stackoverflow answer
Extend the ViewPager class and override the onMeasure() method.
I have a ScrollView that contain one imageView
I want this imageView matching the parent width, full width of the screen and then keep ratio aspect, so wrapping the height.
My options where :
- layout_widht : match_parent
- layout_height : wrap_content
- scaletype : centerCrop
Here is the code
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<ImageView
android:id="#+id/cellarWineImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/etiquette_unknown" />
</LinearLayout>
</ScrollView>
Here is the result
If I just put a fixe height 348dp the result is here
After fighting, I suspect that the wrap content, consider the original height of the image, doesn't matter if the size change due to match parent of the width. Please help for such basic topic. And I hope we can handle this without making any code...
Based on Akshat Agarwal great answer, we can use simple stuff by extending ImageView into a a new component : AspectRatioImageView, and then reusing it directly in the layout.
package com.yourpackage.widgets;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
public class AspectRatioImageView extends ImageView {
public AspectRatioImageView(Context context) {
super(context);
}
public AspectRatioImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AspectRatioImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getDrawable() == null)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
else {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = width * getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth();
setMeasuredDimension(width, height);
}
}
}
Now to use it in the XML:
<com.yourpackage.widgets.AspectRatioImageView android:layout_centerHorizontal="true"
android:src="#drawable/yourdrawable" android:id="#+id/image"
android:layout_alignParentTop="true" android:layout_height="wrap_content"
android:layout_width="match_parent" android:adjustViewBounds="true" />
This works great on my project, by just changing curent ImageView, by this new packageName. Then everything worked perfectly.
Try putting on LinearLayout, ImageView and ScrollView your android:layout_height="fill_parent" to see if works.
Try this way,hope this will help you to solve your problem.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="#+id/cellarWineImageView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="#drawable/ic_launcher"
android:scaleType="fitXY" />
</LinearLayout>
change the layout like this
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:minHeight="348dp"
android:orientation="vertical" >
<ImageView
android:id="#+id/cellarWineImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:minHeight="348dp"
android:src="#drawable/ic_launcher" />
</LinearLayout>
I am trying to display a dynamically-growing list of strings with a checkbox in a GridView, which is itself in a TableLayout.
I can display these "checkboxed" strings fine in a row. My problem occurs when I let the user dynamically add new strings in the GridView.
I created a custom adapter that receives the list of strings. Say we have n strings. The adapter returns 'n + 1' for the items count; in getView, it returns:
a View with a LinearLayout, itself having a CheckBox and an EditText for the first n items,
a LinearLayout with a simple button, with a '+' caption for the 'n + 1'th item.
So far so good. When the '+' button is clicked, I add an empty string to the list of strings and call notifyDataSetChanged in the adapter.
The GridView redraws itself with one more item. BUT it keeps its original height and creates a vertical scrollbar. I'd like the GridView to expand its height (i.e. take up more space on screen and show all items).
I've tried to change the screen to a vertical LinearLayout instead of a TableLayout, but the results is the same.
Here is the layout of my screen:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<!-- other lines omitted -->
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/wine_rack_explanation"
android:layout_gravity="center_vertical" />
<GridView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/gvRack"
android:columnWidth="90dp"
android:numColumns="auto_fit" />
</LinearLayout>
<!-- other lines omitted -->
</LinearLayout>
</ScrollView>
The checkbox + string item from the adapter is defined like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<CheckBox android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/cbCoordinate"
android:checked="true"
/>
<EditText android:id="#+id/txtCoordinate"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
The '+' button item is defined like this:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button android:id="#+id/btnAddBottle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/add_bottle_caption" />
</LinearLayout>
I've tried to call invalidate or invalideViews on the GridView after an item is added. Also called invalidate on the TableLayout and TableRow (in the previous layout of the screen). No success.
Any idea why the GridView refuses to extend its height ?
(Note that I am completely open to using an other viewgroup than the GridView)
Use this code
public class MyGridView extends GridView {
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
I have done this way:
This code will set GridView height as per number of Child.
Note: Where 5 is number of columns.
private void setDynamicHeight(GridView gridView) {
ListAdapter gridViewAdapter = gridView.getAdapter();
if (gridViewAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
int items = gridViewAdapter.getCount();
int rows = 0;
View listItem = gridViewAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalHeight = listItem.getMeasuredHeight();
float x = 1;
if( items > 5 ){
x = items/5;
rows = (int) (x + 1);
totalHeight *= rows;
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight;
gridView.setLayoutParams(params);
}
Hope this will help you.
Developed on the idea shared by https://stackoverflow.com/users/4233197/hiren-patel, so Thank You :)
Pass you GridView and its number of columns through this function and you are done.
private void setGridViewHeightBasedOnChildren(GridView gridView, int noOfColumns) {
ListAdapter gridViewAdapter = gridView.getAdapter();
if (gridViewAdapter == null) {
// adapter is not set yet
return;
}
int totalHeight; //total height to set on grid view
int items = gridViewAdapter.getCount(); //no. of items in the grid
int rows; //no. of rows in grid
View listItem = gridViewAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalHeight = listItem.getMeasuredHeight();
float x;
if( items > noOfColumns ){
x = items/noOfColumns;
//Check if exact no. of rows of rows are available, if not adding 1 extra row
if(items%noOfColumns != 0) {
rows = (int) (x + 1);
}else {
rows = (int) (x);
}
totalHeight *= rows;
//Adding any vertical space set on grid view
totalHeight += gridView.getVerticalSpacing() * rows;
}
//Setting height on grid view
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.height = totalHeight;
gridView.setLayoutParams(params);
}
When onMeasure() is called for GridView, if heightMode is MeasureSpec.UNSPECIFIED, then the gridview will be as tall as all of it's contained elements (plus some padding).
To ensure that this is the case, you can make a quick custom view extending GridView and including the following override:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
}
This is working for me:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/background" >
<!-- MORE LAYOUTS IF YOU WANT -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:fillViewport="true" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- MORE LAYOUTS IF YOU WANT -->
<GridView
android:id="#+id/gridview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:horizontalSpacing="10dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" >
</GridView>
<!-- MORE LAYOUTS IF YOU WANT -->
</RelativeLayout>
</ScrollView>
</RelativeLayout>
Graham's solution did not work for me. However this one (with a bit more hacking) did: https://stackoverflow.com/a/8483078/479478
This is working for me
public class MyGridView extends GridView {
public MyGridView(Context context) {
super(context);
}
public MyGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// set childs height to same value as child that has highest value
for(int i=0; i<getChildCount(); i++) {
MyLinearLayout child = (MyLinearLayout) getChildAt(i);
AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams();
params.height = MyLinearLayout.maxHeight;
child.setLayoutParams(params);
}
// calculate total height and apply to the grid
double numRow = Math.ceil((double) getCount() / (double) getNumColumns());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) this.getLayoutParams();
params.height = (int) numRow * MyLinearLayout.maxHeight;
this.setLayoutParams(params);
// invalidate after change grid's height
this.invalidate();
}
}
MyLinearLayout class
public class MyLinearLayout extends LinearLayout {
public static int maxHeight = 0;
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyLinearLayout(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (maxHeight<this.getMeasuredHeight()) maxHeight=this.getMeasuredHeight();
}
}
The GridView contains some childs of MyLinearLayout, and this is the layout
<?xml version="1.0" encoding="utf-8"?>
<com.mysystem.view.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#ddd"
android:padding="0.5dp"
android:layout_gravity="top"
android:gravity="center_horizontal"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
android:padding="20dp"
android:orientation="vertical">
<ImageView
android:id="#+id/img_menu"
android:layout_width="30dp"
android:layout_gravity="center_horizontal"
android:layout_height="30dp"
android:layout_marginTop="5dp"/>
<TextView
android:id="#+id/tv_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textAlignment="center"
android:textColor="#000"
android:text="Title"
android:textSize="10sp"/>
</LinearLayout>
</com.mysystem.view.MyLinearLayout>