Android Appbarlayout with a large text height issue - android

Appbarlayout has a TextView may contain a large number of text.
At start the TextView is 2 lines and everything is ok, but when I expand the TextView the Appbarlayout is cut and when I scroll up the rest is blank.
Normal:
Expanded:
Scrolled up:
layout code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/view_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.CoordinatorLayout
android:id="#+id/coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/black"
app:elevation="0dp"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/holo_green_dark"
app:layout_scrollFlags="scroll">
<TextView
android:id="#+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:maxLines="2"
android:text="test" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#android:color/holo_blue_bright"
android:text="TAB" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/holo_orange_light"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
</LinearLayout>
activity code:
package me.ffts.demo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
boolean isOpen = false;
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
text.setText("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isOpen) {
text.setMaxLines(2);
isOpen = false;
} else {
text.setMaxLines(Integer.MAX_VALUE);
isOpen = true;
}
}
});
}
}
Is this a bug of AppbarLayout or CoordinatorLayout?

It looks like the AppBarLayout is truncating its height; if you hard code the android:layout_height to something massive, like 2000 dp, you'll see that it is drawing everything. I fixed the issue by forcing the AppBarLayout to measure all of its children, then setting its height.
public class HeightWrappingAppBarLayout extends AppBarLayout {
public HeightWrappingAppBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
height += child.getMeasuredHeight();
}
}
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, height);
}
}

use MeasureSpec.UNSPECIFIED for height.
public class ScrollAppBarLayout extends AppBarLayout {
public ScrollAppBarLayout(Context context) {
super(context);
}
public ScrollAppBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED));
}
#Override
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
int childWidthMeasureSpec;
int childHeightMeasureSpec;
childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, getPaddingLeft()
+ getPaddingRight(), lp.width);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
#Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
int parentHeightMeasureSpec, int heightUsed) {
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}

Related

How can I stretch content inside Coordinator layout to fill empty space?

I am trying to implement behaviour which is shown below (on pictures), so I need to stretch all content below AppBarLayout. I've already achieved it somehow by implementing custom CoordinatorLayout Behaviour but that solution have some issues with views recycling inside RecyclerView and overall performance. Is there easier solution to achieve what i want?
public class TestBehaviour48Margin extends CoordinatorLayout.Behavior {
public TestBehaviour48Margin() {
}
public TestBehaviour48Margin(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean layoutDependsOn(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
return dependency instanceof AppBarLayout;
}
#Override
public boolean onDependentViewChanged(#NonNull CoordinatorLayout parent, #NonNull View child, #NonNull View dependency) {
AppBarLayout appBarLayout = (AppBarLayout) dependency;
val toolbar = appBarLayout.findViewById(R.id.toolbar);
int range = appBarLayout.getTotalScrollRange();
int totalHeight = parent.getHeight();
int appBarHeight = appBarLayout.getHeight();
int toolbarHeight = toolbar.getHeight();
int initialHeight = totalHeight - appBarHeight;
int finalHeight = totalHeight - toolbarHeight;
int differenceHeight = finalHeight - initialHeight;
float factor = -appBarLayout.getY() / range;
val layoutParams = child.getLayoutParams();
int lastHeight = layoutParams.height;
layoutParams.height = (int) (initialHeight + (differenceHeight * factor)) + LayoutUtils.dpToPx(parent.getContext(), 48);
if(lastHeight != layoutParams.height){
child.setLayoutParams(layoutParams);
}
return true;
}
}
<CoordinatorLayout ... (some content)
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="48dp"
android:layout_gravity="bottom"
app:layout_behavior=".custom_views.TestBehaviour48Margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/custom_pink"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:nestedScrollingEnabled="false"
android:id="#+id/rv_strength_items"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#color/grey_B" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="#color/custom_blue_light" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:background="#color/custom_green"
bind:layout_anchor="#id/scroll"
bind:layout_anchorGravity="bottom" />
</LinearLayout>
</FrameLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorSurfaceNight"
android:visibility="#{viewmodel.views.mainLayoutVisibility}"
app:elevation="0dp"
app:layout_behavior=".fragments.training.main_training.view_fold.BlockableAppBarLayoutBehaviour">
... rest of code

How to place a button on top right of a ViewGroup Android?

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.testlayout.MyViewGroup
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|right"
android:text="Hide" />
</com.testlayout.MyViewGroup>
</RelativeLayout>
PercentFrameLayout.java
public class MyViewGroup extends ViewGroup {
private int xPercent = 0;
private int yPercent = 0;
private int widthPercent = 100;
private int heightPercent = 100;
public MyViewGroup(Context context) {
super(context);
}
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private RectF mBorderRect = new RectF();
Paint mBgPaint = new Paint();
public void setPosition(int xPercent, int yPercent, int widthPercent, int heightPercent) {
this.xPercent = xPercent;
this.yPercent = yPercent;
this.widthPercent = widthPercent;
this.heightPercent = heightPercent;
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = getDefaultSize(Integer.MAX_VALUE, widthMeasureSpec);
final int height = getDefaultSize(Integer.MAX_VALUE, heightMeasureSpec);
setMeasuredDimension(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
final int childWidthMeasureSpec =
MeasureSpec.makeMeasureSpec(width * widthPercent / 100, MeasureSpec.AT_MOST);
final int childHeightMeasureSpec =
MeasureSpec.makeMeasureSpec(height * heightPercent / 100, MeasureSpec.AT_MOST);
for (int i = 0; i < getChildCount(); ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
final int width = right - left;
final int height = bottom - top;
// Sub-rectangle specified by percentage values.
final int subWidth = width * widthPercent / 100;
final int subHeight = height * heightPercent / 100;
final int subLeft = left + width * xPercent / 100;
final int subTop = top + height * yPercent / 100;
for (int i = 0; i < getChildCount(); ++i) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
// Center child both vertically and horizontally.
final int childLeft = subLeft + (subWidth - childWidth) / 2;
final int childTop = subTop + (subHeight - childHeight) / 2;
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
// mBorderRect.left = childLeft-100;
// mBorderRect.top = childTop-100;
// mBorderRect.bottom = childHeight+100;
// mBorderRect.right = childWidth+100;
}
}
}
}
What if you put a RelativeLayout inside your MyViewGroup layout like:
<com.testlayout.MyViewGroup
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
</com.testlayout.MyViewGroup>
You just need to set the gravity to the viewgroup
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.testlayout.MyViewGroup
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:gravity="top|right">
<Button
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|right"
android:text="Hide" />
</com.testlayout.MyViewGroup>
</RelativeLayout>

Dynamically add view in raw item of listview with in scrollview not working android

i have one scrollview that is compulsory need it . within scroll view i have one Listview . listview's row item have one framlayout . i am adding nativeexpreesview to fram layout when ad is ready .
now problem is if list have 10 items when ad is not loaded its works okay but when ad is loaded then it occupy some height because i am adding it to frame layout then scroll view scrolls only height of list that is before ad loaded.
but i want scroll with entire item as well ads
My acivity'slayout is below
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/svStrategy"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/app_bg"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical">
<LinearLayout
android:id="#+id/lytBanner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_selector"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_gravity="center"
android:text="#string/str_use_spells_best"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Large"
android:textColor="#android:color/white" />
<ImageView
android:id="#+id/ivBanner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:adjustViewBounds="true" />
</LinearLayout>
<com.example.SummonersWar.classes.NestedListView
android:id="#+id/lvStrategy"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:cacheColorHint="#00000000"
android:divider="#android:color/transparent"
android:dividerHeight="10dp"
android:fadingEdge="none"
android:focusable="false"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
Row_layout of Nestedlistview
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/lytStrategyRow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/list_selector"
android:orientation="horizontal"
android:weightSum="2">
<ImageView
android:id="#+id/ivStrategyIcon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1.4"
android:scaleType="fitXY" />
<TextView
android:id="#+id/tvStrategyTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_margin="5dp"
android:layout_weight="0.6"
android:ellipsize="end"
android:maxLines="4"
android:minLines="4"
android:textAppearance="#android:style/TextAppearance.DeviceDefault.Medium"
android:textColor="#android:color/white" />
</LinearLayout>
<LinearLayout
android:id="#+id/rlads"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/lytStrategyRow"
android:orientation="vertical"
android:visibility="gone">
<View
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="#android:color/transparent" />
<FrameLayout
android:id="#+id/fr_adview"
android:layout_width="match_parent"
android:layout_height="wrap_content"></FrameLayout>
</LinearLayout>
</RelativeLayout>
I am programmatically adding Nativeexpressview to framlayout when ads is loaded.
My nestedlistview below
public class NestedListView extends ListView implements OnScrollListener // OnTouchListener
{
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 100;
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
// setOnTouchListener(this);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null
&& getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition = 0;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null,
this);
// now it will not throw a NPE if listItem is a ViewGroup
// instance
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
newHeight += getPaddingBottom() + getPaddingTop();
}
if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}}
so my problem is scrollview scrolls only height of list when ads are loaded .so please help me what should i do now for scrolling entire list with ads?
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewParent;
import android.widget.ScrollView;
public class VerticalScrollview extends ScrollView {
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
return false;
default:
break;
}
return false;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
return true;
}
}

Android which layout to use to overflow objects to the next line

I am uncertain of what type of layout to use for this certain scenario.
I basically want to have a horizontal linear layout that i can add views to. in this case buttons (displaying tags in an application) But each view will have a different width bases on the name of the tag it is displaying, so i want to add say 10 tags, I need a layout that will fit as many as it can on the 1st line, and then if it doesn't fit, automatically overflow to the next line.
Basically how a text view works with text, if the text is longer than the width it goes to the next line, except I want to do this with non-clickable buttons.
I thought of a grid layout, but then it would have the same no of "tags" on each line when you could have 2 tags with a long name on the first line and 7 with a short name on the second line.
Something that looks a bit like this:
I basically want the look of how stack overflow does it below here.
Answer: Your own custom Layout :)
I know this is a late answer to this question. But it might help the OP or someone for sure.
You can extend ViewGroup to create a custom layout like this one below. The advantage of this is you get the keep the view hierarchy flat.
MyFlowLayout
public class MyFlowLayout extends ViewGroup {
public MyFlowLayout(Context context) {
super(context);
}
public MyFlowLayout(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
public MyFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int realWidth = MeasureSpec.getSize(widthMeasureSpec);
int currentHeight = 0;
int currentWidth = 0;
int currentChildHookPointx = 0;
int currentChildHookPointy = 0;
int childCount = this.getChildCount();
for(int i = 0; i < childCount; i++) {
View child = getChildAt(i);
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
//check if child can be placed in the current row, else go to next line
if(currentChildHookPointx + childWidth > realWidth) {
//new line
currentWidth = Math.max(currentWidth, currentChildHookPointx);
//reset for new line
currentChildHookPointx = 0;
currentChildHookPointy += childHeight;
}
int nextChildHookPointx;
int nextChildHookPointy;
nextChildHookPointx = currentChildHookPointx + childWidth;
nextChildHookPointy = currentChildHookPointy;
currentHeight = Math.max(currentHeight, currentChildHookPointy + childHeight);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.x = currentChildHookPointx;
lp.y = currentChildHookPointy;
currentChildHookPointx = nextChildHookPointx;
currentChildHookPointy = nextChildHookPointy;
}
currentWidth = Math.max(currentChildHookPointx, currentWidth);
setMeasuredDimension(resolveSize(currentWidth, widthMeasureSpec),
resolveSize(currentHeight, heightMeasureSpec));
}
#Override
protected void onLayout(boolean b, int left, int top, int right, int bottom) {
//call layout on children
int childCount = this.getChildCount();
for(int i = 0; i < childCount; i++) {
View child = this.getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight());
}
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MyFlowLayout.LayoutParams(getContext(), attrs);
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new MyFlowLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
#Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new MyFlowLayout.LayoutParams(p);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof MyFlowLayout.LayoutParams;
}
public static class LayoutParams extends ViewGroup.MarginLayoutParams {
int spacing = -1;
int x = 0;
int y = 0;
LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray t = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout);
spacing = t.getDimensionPixelSize(R.styleable.FlowLayout_Layout_layout_space, 0);
t.recycle();
}
LayoutParams(int width, int height) {
super(width, height);
spacing = 0;
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
Usage in a layout.xml file
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:cl="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.merryapps.customlayout.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<com.merryapps.customlayout.MyFlowLayout
android:id="#+id/flw1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF0000">
<Button
android:id="#+id/b1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello"
cl:layout_space="20dp"/>
<Button
android:id="#+id/b2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/world"/>
<Button
android:id="#+id/b4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/world"/>
<Button
android:id="#+id/b5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/world"/>
<Button
android:id="#+id/b6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/world"/>
</com.merryapps.customlayout.MyFlowLayout>
<Button
android:id="#+id/b3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/world"
android:textAllCaps="false"/>
</LinearLayout>
For show type of view one must go for flow layout :-
There are many libraries available on Git
Following is the example of,
blazsolar/FlowLayout
Add this line in app.gradle
compile "com.wefika:flowlayout:<version>"
Usage:-
<com.wefika.flowlayout.FlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start|top">
<View
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lorem ipsum" />
</com.wefika.flowlayout.FlowLayout>
For detail implementation follow below link-
https://github.com/blazsolar/FlowLayout
You can try this links too:-
https://github.com/xiaofeng-han/AndroidLibs/tree/master/flowlayoutmanager (try this)
https://github.com/ApmeM/android-flowlayout
https://gist.github.com/hzqtc/7940858

Android list view inside a scroll view

I have an android layout which has a scrollView with a number of elements with in it. At the bottom of the scrollView I have a listView which is then populated by an adapter.
The problem that I am experiencing, is that android is excluding the listView from the scrollView as the scrollView already has a scroll-able function. I want the listView to be as long as the content is and for the master scroll view to be scroll-able.
How can I achieve this behavior?
Here is my main layout:
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:fillViewport="true"
android:gravity="top" >
<LinearLayout
android:id="#+id/foodItemActvity_linearLayout_fragments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
I then programmatically add my components to the linearlayour with the id: foodItemActvity_linearLayout_fragments. Below is one of the views that is loaded into that linearlayout. This is the one giving me trouble with the scrolls.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/fragment_dds_review_textView_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reviews:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ListView
android:id="#+id/fragment_dds_review_listView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
My adapter then fills up this list view.
Here is an image from the android hierarchy viewer when I click on the master scrollView:
As you can see, it is excluding the reviews listView.
I should be able to scroll the page down and see 8 reviews, but instead it only shows me those 3, and I can scroll on the tiny part where the reviews are. I want a global page scroll
For any Child view to scroll inside a ScrollView. Anything like ListView, RecyclerView, etc. You just have to replace ScrollView with androidx.core.widget.NestedScrollView in your current xml and then magic happens.
Below is a sample xml code :
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
android:paddingBottom="20dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Recycler View inside a Scroll View"
android:textColor="#color/black"
android:textSize="#dimen/_20sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Below is a Recycler View as an example."
android:textSize="16sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:layout_constraintTop_toBottomOf="#id/et_damaged_qty" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="This textview automatically goes below the Recycler View."
android:textSize="16sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.core.widget.NestedScrollView>
Now you can get rid of all the ugly hacks you did to get around with nested scrolling.
The answer is simple and I am surprised it has yet to be answered here.
Use a Header View or/and Footer View on the list itself.
Don't mix a ScrollView with a ListView or anything that can scroll. It's meant to be used with headers and footers :)
Essentially, take all the content above your ListView, put it in another .xml file as a layout and then in code inflate it and add it to the list as a header view.
i.e.
View header = getLayoutInflater().inflate(R.layout.header, null);
View footer = getLayoutInflater().inflate(R.layout.footer, null);
listView.addHeaderView(header);
listView.addFooterView(footer);
I know it's been so long but I got this problem too, tried this solution and it's working. So I guess it may help the others too.
I add android:fillViewport="true" on the layout xml for the scrollView.
So overall my ScrollView will be like this.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollView6"
android:fillViewport="true">
And it works like magic to me.
the ListView that located inside my ScrollView expand to its size again.
Here is the full example code for the ScrollView and the ListView.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollView6" android:fillViewport="true">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
....
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/lv_transList" android:layout_gravity="top"
android:layout_marginTop="5dp"/>
....
</LinearLayout>
</ScrollView>
You Create Custom ListView Which is non Scrollable
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
In Your Layout Resources File
<?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="match_parent"
android:fadingEdgeLength="0dp"
android:fillViewport="true"
android:overScrollMode="never"
android:scrollbars="none" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- com.Example Changed with your Package name -->
<com.Example.NonScrollListView
android:id="#+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.Example.NonScrollListView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/lv_nonscroll_list" >
<!-- Your another layout in scroll view -->
</RelativeLayout>
</RelativeLayout>
</ScrollView>
In Java File
Create a object of your customListview instead of ListView like :
NonScrollListView non_scroll_list = (NonScrollListView) findViewById(R.id.lv_nonscroll_list);
public static void setListViewHeightBasedOnChildren(ListView listView) {
// 获取ListView对应的Adapter
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0, len = listAdapter.getCount(); i < len; i++) { // listAdapter.getCount()返回数据项的数目
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0); // 计算子项View 的宽高
totalHeight += listItem.getMeasuredHeight(); // 统计所有子项的总高度
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
// listView.getDividerHeight()获取子项间分隔符占用的高度
// params.height最后得到整个ListView完整显示需要的高度
listView.setLayoutParams(params);
}
you can use this code for listview in scrollview
Don't do anything in Parent ScrollView. Only do this to child ListView. Everything will work perfectly.
mListView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
mScrollView.requestDisallowInterceptTouchEvent(true);
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_UP:
mScrollView.requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
});
This code will solve your problem if you have implemented just a ListView in a code.
If you are using RelativeLayout as ListView child than this code return a NullPointerException here listItem.measure(0, 0);, because of RelativeLayout.And the solution is put your Relativelayout inside a LinearLayout and it will work fine.
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
You may solve it by adding android:fillViewport="true" to your ScrollView.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:fillViewport="true"
android:scrollbars="vertical">
<ListView
android:id="#+id/statusList"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:animationCache="false"
android:divider="#null"
android:scrollingCache="false"
android:smoothScrollbar="true" />
</ScrollView>
before use that property, there was only one child of my list view is visible. after using that all the rows or child of list are visible.
I'll leave it here in case anyone will face the same issue. I had to put a ListView inside a ScrollView. ListView with header was not an option by a number of reasons. Neither was an option to use LinearLayout instead of ListView. So I followed the accepted solution, but it didn't work because items in the list had complex layout with multiple rows and each listview item was of variable height. Height was measured not properly. The solution was to measure each item inside ListView Adapter's getView() method.
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view == null) {
. . .
view.setTag(holder);
} else holder = (ViewHolder)view.getTag();
. . .
// measure ListView item (to solve 'ListView inside ScrollView' problem)
view.measure(View.MeasureSpec.makeMeasureSpec(
View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
return view;
}
You can easy put ListView in ScrollView!
Just need to change height of ListView programmatically, like this:
ViewGroup.LayoutParams listViewParams = (ViewGroup.LayoutParams)listView.getLayoutParams();
listViewParams.height = 400;
listView.requestLayout();
This works perfectly!
Done after lots of R&D:
fragment_one.xml should looks like:
<?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="match_parent"
android:id="#+id/scrollViewParent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="400dip" >
<ListView
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="#+id/customView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/transparent" />
</RelativeLayout>
<!-- Your other elements are here -->
</LinearLayout>
</ScrollView>
Your Java class of FragmentOne.java looks like:
private ListView listView;
private View customView
onCreateView
listView = (ListView) rootView.findViewById(R.id.listView);
scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent);
customView = (View)rootView.findViewById(R.id.customView);
customView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
scrollViewParent.requestDisallowInterceptTouchEvent(true);
// Disable touch on transparent view
return false;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
scrollViewParent.requestDisallowInterceptTouchEvent(false);
return true;
case MotionEvent.ACTION_MOVE:
scrollViewParent.requestDisallowInterceptTouchEvent(true);
return false;
default:
return true;
}
}
});
My requirement is to include a ListView of equally-sized items within a ScrollView. I tried a few of the other solutions listed here, none seemed to size the ListView correctly (either too little space or too much). Here's what worked for me:
public static void expandListViewHeight(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
ViewGroup.LayoutParams params = listView.getLayoutParams();
listView.measure(0, 0);
params.height = listView.getMeasuredHeight() * listAdapter.getCount() + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
Hope this helps someone.
I had a similar problem to the issue posed by the Original Poster - how to make the listview scroll inside the scrollview - and this answer solved my problem.
Disable scrolling of a ListView contained within a ScrollView
I didn't call new fragments into existing layouts or anything like that, like the OP was doing, so my code would look something like this :
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:fillViewport="true"
android:gravity="top" >
<LinearLayout
android:id="#+id/foodItemActvity_linearLayout_fragments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/fragment_dds_review_textView_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Reviews:"
android:textAppearance="?android:attr/textAppearanceMedium" />
<ListView
android:id="#+id/my_listView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
</ScrollView>
Basically what I am doing is checking the length of the listview before I call it and when I call it I make it into that length. In your java class use this function:
public static void justifyListViewHeightBasedOnChildren (ListView listView) {
ListAdapter adapter = listView.getAdapter();
if (adapter == null) {
return;
}
ViewGroup vg = listView;
int totalHeight = 0;
for (int i = 0; i < adapter.getCount(); i++) {
View listItem = adapter.getView(i, null, vg);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams par = listView.getLayoutParams();
par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
listView.setLayoutParams(par);
listView.requestLayout();
}
And call the function like this:
justifyListViewHeightBasedOnChildren(listView);
The result is a listview with no scrollbar, the whole length of the listview being displayed, that scrolls with the scroll bar of the scrollview.
As others had already mentioned, don't use ListView inside a ScrollView.
To workaround, you can use a LinearLayout, but to still keep things neat - populate your LinearLayout with an Adapter, same as you do with a ListView
You can use this class as a LinearLayout replacement that supports Adapters
import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
public class AdaptableLinearLayout extends LinearLayout {
private BaseAdapter mAdapter;
private int mItemCount = 0;
private boolean mDisableChildrenWhenDisabled = false;
private int mWidthMeasureSpec;
private int mHeightMeasureSpec;
public AdaptableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public BaseAdapter getAdapter() {
return mAdapter;
}
public void setAdapter(BaseAdapter adapter) {
mAdapter = adapter;
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
updateLayout();
super.onChanged();
}
#Override
public void onInvalidated() {
updateLayout();
super.onInvalidated();
}
});
updateLayout();
}
private void updateLayout() {
mItemCount = mAdapter.getCount();
requestLayout();
invalidate();
}
/**
* set size for the current View
*/
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidthMeasureSpec = widthMeasureSpec;
mHeightMeasureSpec = heightMeasureSpec;
removeAllViewsInLayout();
for (int i = 0; i < mItemCount; i++) {
makeAndAddView(i);
}
}
private View makeAndAddView(int position) {
View child;
// Nothing found in the recycler -- ask the adapter for a view
child = mAdapter.getView(position, null, this);
// Position the view
setUpChild(child, position);
return child;
}
private void setUpChild(View child, int position) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (lp == null) {
lp = generateDefaultLayoutParams();
}
addViewInLayout(child, position, lp);
// Get measure specs
int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, getPaddingTop() + getPaddingBottom(), lp.height);
int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, getPaddingLeft() + getPaddingRight(), lp.width);
// Measure child
child.measure(childWidthSpec, childHeightSpec);
int childLeft;
int childRight;
// Position vertically based on gravity setting
int childTop = getPaddingTop() + ((getMeasuredHeight() - getPaddingBottom() - getPaddingTop() - child.getMeasuredHeight()) / 2);
int childBottom = childTop + child.getMeasuredHeight();
int width = child.getMeasuredWidth();
childLeft = 0;
childRight = childLeft + width;
child.layout(childLeft, childTop, childRight, childBottom);
if (mDisableChildrenWhenDisabled) {
child.setEnabled(isEnabled());
}
}
}
You can put all into linear layout. That is, create linear layout and it will have 2 childs, scrollview and another linear layout. Give them layout weights and here you go :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ScrollView
android:layout_width="fill_parent"
android:layout_height="0dip" android:layout_weight="0.8">
<LinearLayout
android:id="#+id/seTaskActivityRoot"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/white"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/taskName" />
<Spinner
android:id="#+id/seTaskPrioritiesSP"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/taskTargetInNumeric" />
<Spinner
android:id="#+id/seTaskUnitsSP"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="#+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/newTaskCurrentStatus" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:hint="#string/addTaskCurrentStatus"
android:inputType="numberDecimal" />
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:orientation="vertical" android:layout_weight="0.2">
<TextView
android:id="#+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<ListView
android:id="#+id/logList"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.
http://developer.android.com/reference/android/widget/ScrollView.html
Best solution is add this android:nestedScrollingEnabled="true" attribute in child scrolling for example i have inserted this attribute in my ListView that is child of ScrollView. i hope this mathod works for you :-
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="TextView"/>
<ListView
android:nestedScrollingEnabled="true" //add this only
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="300dp"/>
</LinearLayout>
</ScrollView>
Do NEVER put a ListView inside of a ScrollView! You can find more information about that topic on Google. In your case, use a LinearLayout instead of the ListView and add the elements programmatically.
Update
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:fillViewport="true"
android:gravity="top" >
<LinearLayout
android:id="#+id/foodItemActvity_linearLayout_fragments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
to
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="2"
android:fillViewport="true"
android:gravity="top" >
<LinearLayout
android:id="#+id/foodItemActvity_linearLayout_fragments"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
The point here is you are trying to set height to 0dp (fixed)
found a solution for scrollview -> viewpager -> FragmentPagerAdapter -> fragment -> dynamic listview, but im not the author. there is some bugs, but at least it works
public class CustomPager extends ViewPager {
private View mCurrentView;
public CustomPager(Context context) {
super(context);
}
public CustomPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
this.post(new Runnable() {
#Override
public void run() {
requestLayout();
}
});
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private int mCurrentPosition = -1;
public MyPagerAdapter(FragmentManager fm) {
super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged()
this.fragments = new ArrayList<Fragment>();
fragments.add(new FirstFragment());
fragments.add(new SecondFragment());
fragments.add(new ThirdFragment());
fragments.add(new FourthFragment());
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
Fragment fragment = (Fragment) object;
CustomPager pager = (CustomPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
}
fragments layout can be anything
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment">
<ListView
android:id="#+id/lv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#991199"/>
</LinearLayout>
then somewhere just
lv = (ListView) view.findViewById(R.id.lv1);
lv.setAdapter(arrayAdapter);
setListViewHeightBasedOnChildren(lv);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth,
LinearLayout.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
using this ListView Worked for me
package net.londatiga.android.widget;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;
import android.content.Context;
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;
}
}
and in xml
<com.pakagename.ExpandableHeightListView
android:id="#+id/expandableHeightListView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.Example.ExpandableHeightListView>
and in MainActivity
ExpandableHeightListView listView = new ExpandableHeightListView(this);
listview=(ExpandableHeightListView)findViewById(R.id.expandableHeightListView);
listView.setAdapter(adapter); //set your adaper
listView.setExpanded(true);
Refer This article for more info and also to know how to keep gridview inside scroll view
It is not possible to use Scroll-view inside List-view as List-view already has scrolling property.
To use list-view inside Scroll-view you can follow these steps which worked for me :
1) Create NonScrollListView java file that disable the default scrolling property of list-view. and code is below
package your-package-structure;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
2) Now create xml file which which has NestedScrollView and inside this use NonScrollListView for listing your items. This will make your entire screen to scroll with all the views.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<ViewFlipper
android:id="#+id/v_flipper"
android:layout_width="match_parent"
android:layout_height="130dp">
</ViewFlipper>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="SHOP"
android:textSize="15dp"
android:textStyle="bold"
android:gravity="center"
android:padding="5dp"
android:layout_marginTop="15dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="#ddd"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1"
>
<com.abc.xyz.NonScrollListView
android:id="#+id/listview"
android:divider="#null"
android:layout_width="match_parent"
android:layout_marginBottom="10dp"
android:layout_height="match_parent"
android:padding="8dp">
</com.abc.xyz.NonScrollListView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom">
<include layout="#layout/footer" />
</LinearLayout>
</LinearLayout>
3) Now in java class i.e, home.java define NonScrollListView instead of Listview.
package comabc.xyz.landscapeapp;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.Toolbar;
import android.widget.ViewFlipper;
public class home extends Fragment {
int pos = 0;
ViewFlipper v_flipper;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_home, container, false);
return view;
}
#Override
public void onViewCreated(#NonNull final View view, #Nullable Bundle savedInstanceState) {
NonScrollListView listView = (NonScrollListView) view.findViewById(R.id.listview);
customAdapter customAdapter = new customAdapter(getActivity());
listView.setAdapter(customAdapter);
listView.setFocusable(false);
customAdapter.notifyDataSetChanged();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Log.d("listview click", "onItemClick: ");
/* FragmentTransaction fr = getFragmentManager().beginTransaction().replace(R.id.fragment_container, new productdisplay());
fr.putExtra("Position", position);
fr.addToBackStack("tag");
fr.commit();*/
Intent intent = new Intent(getActivity(), productdisplay.class);
intent.putExtra("Position", position);
startActivity(intent);
}
});
//image slider
int images[] = {R.drawable.slide1, R.drawable.slide2, R.drawable.slide3};
v_flipper = view.findViewById(R.id.v_flipper);
for (int image : images) {
flipperImages(image);
}
}
private void flipperImages(int image) {
ImageView imageView = new ImageView(getActivity());
imageView.setBackgroundResource(image);
v_flipper.addView(imageView);
v_flipper.setFlipInterval(4000);
v_flipper.setAutoStart(true);
v_flipper.setInAnimation(getActivity(), android.R.anim.slide_in_left);
v_flipper.setOutAnimation(getActivity(), android.R.anim.slide_out_right);
}
}
Note: I used Fragments here.
Ok, here 's my answer. The method that fixes the ListView height is closed enough, but not perfect. In case that most of the items are the same height, that work well. But in case that's not, then there's a big problem. I've tried many time, and when I put out the value of listItem.getMeasureHeight and listItem.getMeasuerWidth into the log, I saw the width values vary a lot, which is not expected here, since all the item in the same ListView should have the same width. And there go the bug :
Some used measure(0 ,0), which actually made the view unbound, in both direction, and width run wild. Some tried to getWidth of listView, but then it return 0, meaningless.
When I read further into how android render the View, I realize that all of this attempt can't reach the answer that I searched for, unless these function run after the view is render.
This time I use the getViewTreeObserver on the ListView that I want to fix height, then addOnGlobalLayoutListener. Inside this method, I declare a new OnGlobalLayoutListener, in which, this time, getWidth return the actual width of the ListView.
private void getLayoutWidth(final ListView lv, final int pad){
//final ArrayList<Integer> width = new ArrayList<Integer>();
ViewTreeObserver vto = lv.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
lv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
//width.add(layout.getMeasuredWidth());
int width = lv.getMeasuredWidth();
ListUtils.setDynamicHeight(lv, width, pad);
}
});
}
public static class ListUtils {
//private static final int UNBOUNDED = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
public static void setDynamicHeight(ListView mListView, int width, int pad) {
ListAdapter mListAdapter = mListView.getAdapter();
mListView.getParent();
if (mListAdapter == null) {
// when adapter is null
return;
}
int height = 0;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(width - 2*pad, View.MeasureSpec.EXACTLY);
for (int i = 0; i < mListAdapter.getCount(); i++) {
View listItem = mListAdapter.getView(i, null, mListView);
listItem.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
//listItem.measure(UNBOUNDED, UNBOUNDED);
height += listItem.getMeasuredHeight() + 2*pad;
Log.v("ViewHeight :", mListAdapter.getClass().toString() + " " + listItem.getMeasuredHeight() + "--" + listItem.getMeasuredWidth());
}
ViewGroup.LayoutParams params = mListView.getLayoutParams();
params.height = height + (mListView.getDividerHeight() * (mListAdapter.getCount() - 1));
mListView.setLayoutParams(params);
mListView.requestLayout();
}
}
The value pad, is the padding that I set in ListView layout.
If for some reason you don't want to use addHeaderView and addFooterView, e.g. when you have several lists, a good idea would be to reuse ListAdapter to populate a simple LinearLayout so there's no scrolling functionality.
If you already have a whole fragment derived from ListFragment and want to convert it to a similar fragment with simple LinearLayout without scrolling instead (e.g. to put it in ScrollView), you can implement an adapter fragment like this:
// converts listFragment to linearLayout (no scrolling)
// please call init() after fragment is inflated to set listFragment to convert
public class ListAsArrayFragment extends Fragment {
public ListAsArrayFragment() {}
private ListFragment mListFragment;
private LinearLayout mRootView;
// please call me!
public void init(Activity activity, ListFragment listFragment){
mListFragment = listFragment;
mListFragment.onAttach(activity);
mListFragment.getListAdapter().registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
refreshView();
}
});
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// create an empty vertical LinearLayout as the root view of this fragment
mRootView = new LinearLayout(getActivity());
mRootView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mRootView.setOrientation(LinearLayout.VERTICAL);
return mRootView;
}
// reusing views for performance
// todo: support for more than one view type
ArrayList<View> mViewsToReuse = new ArrayList<>();
ArrayList<View> mCurrentViews = new ArrayList<>();
// re-add views to linearLayout
void refreshView(){
// remove old views from linearLayout and move them to mViewsToReuse
mRootView.removeAllViews();
mViewsToReuse.addAll(mCurrentViews);
mCurrentViews.clear();
// create new views
for(int i=0; i<mListFragment.getListAdapter().getCount(); ++i){
View viewToReuse = null;
if(!mViewsToReuse.isEmpty()){
viewToReuse = mViewsToReuse.get(mViewsToReuse.size()-1);
mViewsToReuse.remove(mViewsToReuse.size()-1);
}
final View view = mListFragment.getListAdapter().getView(i, viewToReuse, mRootView);
ViewGroup.LayoutParams oldParams = view.getLayoutParams();
view.setLayoutParams(new LinearLayout.LayoutParams(oldParams.width, oldParams.height));
final int finalI = i;
// pass click events to listFragment
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListFragment.onListItemClick(null, view, finalI, finalI);
}
});
mRootView.addView(view);
mCurrentViews.add(view);
}
}
You may also want to forward onCreate, onPause, onResume, etc. to the original fragment depending on your needs or try inheritance instead of composition (but override certain methods so original fragment is not actually attached to layout hierarchy); but I wanted to isolate original fragment as much as possible, because we only need to extract its ListAdapter. If you call original fragment's setListAdapter in onAttach, that's probably enough.
Here's how to use ListAsArrayFragment to include OriginalListFragment without scrolling. In parent activity's onCreate:
ListAsArrayFragment fragment = (ListAsArrayFragment) getFragmentManager().findFragmentById(R.id.someFragmentId);
OriginalListFragment originalFragment = new OriginalListFragment();
fragment.init(this, originalFragment);
// now access originalFragment.getListAdapter() to modify list entries
// and remember to call notifyDatasetChanged()
found a solution for scrollview -> viewpager -> FragmentPagerAdapter -> fragment -> dynamic listview, but im not the author.
public class CustomPager extends ViewPager {
private View mCurrentView;
public CustomPager(Context context) {
super(context);
}
public CustomPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
this.post(new Runnable() {
#Override
public void run() {
requestLayout();
}
});
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private int mCurrentPosition = -1;
public MyPagerAdapter(FragmentManager fm) {
super(fm);//or u can set them separately, but dont forget to call notifyDataSetChanged()
this.fragments = new ArrayList<Fragment>();
fragments.add(new FirstFragment());
fragments.add(new SecondFragment());
fragments.add(new ThirdFragment());
fragments.add(new FourthFragment());
}
#Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
Fragment fragment = (Fragment) object;
CustomPager pager = (CustomPager) container;
if (fragment != null && fragment.getView() != null) {
mCurrentPosition = position;
pager.measureCurrentView(fragment.getView());
}
}
}
#Override
public Fragment getItem(int position) {
return fragments.get(position);
}
#Override
public int getCount() {
return fragments.size();
}
}
fragments layout can be anything
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent" tools:context="nevet.me.wcviewpagersample.FirstFragment">
<ListView
android:id="#+id/lv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#991199"/>
</LinearLayout>
then somewhere just
lv = (ListView) view.findViewById(R.id.lv1);
lv.setAdapter(arrayAdapter);
setListViewHeightBasedOnChildren(lv);
}
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null)
return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0)
view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth,
LinearLayout.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
In xml:
<com.example.util.NestedListView
android:layout_marginTop="10dp"
android:id="#+id/listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#null"
android:layout_below="#+id/rl_delivery_type" >
</com.example.util.NestedListView>
In Java:
public class NestedListView extends ListView implements View.OnTouchListener, AbsListView.OnScrollListener {
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
public NestedListView(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
setOnTouchListener(this);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition = 0;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null, this);
//now it will not throw a NPE if listItem is a ViewGroup instance
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
}
if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, 1);
}
}
return false;
}
}
Just call this function after assign adapter to listview
public static void setListViewHeightBasedOnChildren
(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) return;
int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(),
View.MeasureSpec.UNSPECIFIED);
int totalHeight = 0;
View view = null;
for (int i = 0; i < listAdapter.getCount(); i++) {
view = listAdapter.getView(i, view, listView);
if (i == 0) view.setLayoutParams(new
ViewGroup.LayoutParams(desiredWidth,
ViewGroup.LayoutParams.WRAP_CONTENT));
view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED);
totalHeight += view.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() *
(listAdapter.getCount() - 1));
listView.setLayoutParams(params);
listView.requestLayout();
}
if you what show all items in listView inside ScrollView use this code
val params: ViewGroup.LayoutParams = listView!!.layoutParams
params.height = useitemsList.size * 200 //add static height
listView!!.layoutParams = params
listView!!.requestLayout()
Just set the value of required height in a listview height attribute inside a parent scrollview. It will scroll along with other parents child item.
This worked for me (link1, link2):
You Create Custom ListView Which is non Scrollable
public class NonScrollListView extends ListView {
public NonScrollListView(Context context) {
super(context);
}
public NonScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NonScrollListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int heightMeasureSpec_custom = View.MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
}
}
In Your Layout File
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<!-- com.Example Changed with your Package name -->
<com.thedeveloperworldisyours.view.NonScrollListView
android:id="#+id/lv_nonscroll_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</com.thedeveloperworldisyours.view.NonScrollListView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/lv_nonscroll_list" >
<!-- Your another layout in scroll view -->
</RelativeLayout>
</RelativeLayout>
</ScrollView>
Create a object of your customListview instead of ListView like :
NonScrollListView non_scroll_list = (NonScrollListView) findViewById(R.id.lv_nonscroll_list);

Categories

Resources