I am having trouble in getting the GridView content height programmatically since I am placing it inside a ScrollView, I just need to stretch the GridView height dynamically by getting its content height in PIXELS. Here's what I did:
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
System.out.println("...111Height..."+gridView.getMeasuredWidth());
}
but I want to obtain the value inside OnCreate so that I can feed it to layoutParams.height in:
GridView gridView = (GridView) findViewById(R.id.gridview_module);
ViewGroup.LayoutParams layoutParams = gridView.getLayoutParams();
layoutParams.height = convertDpToPixels(iDontKnowWhatToPutHere, this);
gridView.setLayoutParams(layoutParams);
and the method to convert from pixels to dp:
public static int convertDpToPixels(float dp, Context context) {
Resources resources = context.getResources();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
resources.getDisplayMetrics());
}
EDIT:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainLayout"
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=".SecondActivity" >
<ScrollView
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="0"
android:layout_weight="1"
android:fillViewport="true"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
<com.example.ExpandableHeightGridView
android:id="#+id/gridview_module"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/tv"
android:layout_weight="1"
android:gravity="center"
android:horizontalSpacing="20dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
<Button
android:id="#+id/dial_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/gridview_module"
android:onClick="dialPhone"
android:text="Dial Phone" />
</LinearLayout>
</ScrollView>
To achieve this you need to create CustomGridview like this
public class CustomGridView extends GridView {
private int old_count;
private android.view.ViewGroup.LayoutParams params;
private boolean isExpandFully = false;
private int verticleSpacing = 4;
private int noOfCollumns = 1;
public int getNumColumns() {
return noOfCollumns;
}
public void setNoOfCollumns(int noOfCollumns) {
this.noOfCollumns = noOfCollumns;
}
public int getVerticleSpacing() {
return verticleSpacing;
}
public void setVerticleSpacing(int verticleSpacing) {
this.verticleSpacing = verticleSpacing;
}
public void setExpandFully(boolean isExpandFully) {
this.isExpandFully = isExpandFully;
}
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomGridView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomGridView(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
String namespace = "http://schemas.android.com/apk/res/android";
noOfCollumns = attrs.getAttributeIntValue(namespace, "numColumns", 1);
}
}
#Override
protected void onDraw(Canvas canvas) {
setVerticalSpacing(getVerticleSpacing());
if (isExpandFully) {
try {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
int len = (getCount() % getNumColumns() == 0 ? getCount() / getNumColumns() : getCount() / getNumColumns() + 1);
params.height = 0;
for (int i = 0; i < len; i++) {
params.height = params.height + (old_count > 0 ? getChildAt(0).getHeight() + getVerticleSpacing() : 0);
}
params.height += 10;
setLayoutParams(params);
}
} catch (Exception e) {
}
}
super.onDraw(canvas);
}
}
how to use
CustomGridView myGridview = (CustomGridView)findViewById(R.id.customGridview);
myGridview.setExpandFully(true);
Related
I have the following XML file that is built out of a custom layout that is created via Java code and 3 buttons inside a linear layout below it -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#color/grey_200"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/grey_200"
android:gravity="center_vertical"
android:orientation="vertical"
tools:layout_height="500dp">
<com.etiennelawlor.tinderstack.ui.TinderStackLayout
android:id="#+id/activity_main_tinder_stack_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<Button
android:layout_width="wrap_content"
android:id="#+id/activity_main_delete_button"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#ff0000"
android:tag="1"
android:text="#string/activity_main_delete" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/activity_main_pass_button"
android:layout_margin="10dp"
android:background="#A9A9A9"
android:tag="2"
android:text="#string/activity_main_pass" />
<Button
android:layout_width="wrap_content"
android:id="#+id/activity_main_approve_button"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#98FB98"
android:tag="3"
android:text="#string/activity_main_approve" />
</LinearLayout>
</LinearLayout>
The issue I am facing looks like this -
I want the image to be able to move on top of the buttons when touching it, but also of course for the buttons to be touchable and functional.
Here is my TinderStackLayout class -
public class TinderStackLayout extends FrameLayout {
// Constants
private static final int DURATION = 300;
// Variable members
private OnCardSwipedListener onCardSwipedListener;
private int screenWidth;
private int yMultiplier;
//Top card
private TinderCardView topCardOnStack;
private Button mDeleteButton, mPassButton, mApproveButton;
//Constructors
public TinderStackLayout(Context context) {
super(context);
init();
}
public TinderStackLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TinderStackLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
if (onCardSwipedListener != null)
onCardSwipedListener.onNext(getChildCount());
}
#Override
public void removeView(View view) {
super.removeView(view);
if (onCardSwipedListener != null)
onCardSwipedListener.onNext(getChildCount());
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
// Helper Methods
private void init() {
setClipChildren(false);
screenWidth = DisplayUtility.getScreenWidth(getContext());
yMultiplier = DisplayUtility.dp2px(getContext(), 8);
mDeleteButton = new Button(getContext());
mPassButton = new Button(getContext());
mApproveButton = new Button(getContext());
}
public void addCard(TinderCardView tinderCardView) {
View firstCard = getChildAt(0);
if (firstCard != null && firstCard.equals(tinderCardView)) {
return;
}
if (onCardSwipedListener == null)
onCardSwipedListener = tinderCardView.getOnCardSwipedListener();
topCardOnStack = tinderCardView;
ViewGroup.LayoutParams layoutParams;
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int childCount = getChildCount();
addView(tinderCardView, 0, layoutParams);
float scaleValue = 1 - (childCount / 50.0f);
tinderCardView.animate()
.x(0)
.y(childCount * yMultiplier)
.scaleX(scaleValue)
.setInterpolator(new AnticipateOvershootInterpolator())
.setDuration(DURATION);
}
public TinderCardView getTopCardOnStack() {
return topCardOnStack;
}
}
Do I need to add them dynamically? or is there a simpler way?
And if I do need to add them dynamically - I would be happy to get a code example of how to do so.
In this below code i want to set center_horizontal as attachmentSlidingLayer view id but layout_gravity and gravity for parent and child view doesn't work correctly and by default gravity is left side
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:slidingLayer="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<io.codetail.widget.RevealFrameLayout <!-- extends from FrameLayout -->
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal">
<com.test.libraries.SlidingLayer <!-- extends from BoundedFrameLayout-->
android:id="#+id/attachmentSlidingLayer"
android:layout_width="match_parent"
android:layout_height="210dp"
android:layout_gravity="center_horizontal"
android:elevation="5dp"
app:bounded_width="450dp"
android:foregroundGravity="center_horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center_horizontal"
android:background="#drawable/sheet_shadow"
android:orientation="vertical"
app:bounded_width="450dp">
</LinearLayout>
</<com.test.libraries.SlidingLayer.SlidingLayer >
</io.codetail.widget.RevealFrameLayout>
</android.support.design.widget.CoordinatorLayout>
BoundedFrameLayout class:
public class BoundedFrameLayout extends FrameLayout {
private final int mBoundedWidth;
private final int mBoundedHeight;
public BoundedFrameLayout(Context context) {
super(context);
mBoundedWidth = 0;
mBoundedHeight = 0;
}
public BoundedFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);
mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);
mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);
a.recycle();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Adjust width as necessary
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
if (mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
int measureMode = MeasureSpec.getMode(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
}
// Adjust height as necessary
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
if (mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
int measureMode = MeasureSpec.getMode(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
RevealFrameLayout class:
public class RevealFrameLayout extends FrameLayout implements RevealAnimator{
private Path mRevealPath;
private final Rect mTargetBounds = new Rect();
private RevealInfo mRevealInfo;
private boolean mRunning;
private float mRadius;
public RevealFrameLayout(Context context) {
this(context, null);
}
public RevealFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RevealFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mRevealPath = new Path();
}
#Override
public void onRevealAnimationStart() {
mRunning = true;
}
#Override
public void onRevealAnimationEnd() {
mRunning = false;
invalidate(mTargetBounds);
}
#Override
public void onRevealAnimationCancel() {
onRevealAnimationEnd();
}
#Override
public void setRevealRadius(float radius){
mRadius = radius;
mRevealInfo.getTarget().getHitRect(mTargetBounds);
invalidate(mTargetBounds);
}
#Override
public float getRevealRadius(){
return mRadius;
}
#Override
public void attachRevealInfo(RevealInfo info) {
mRevealInfo = info;
}
#Override
public SupportAnimator startReverseAnimation() {
if(mRevealInfo != null && mRevealInfo.hasTarget() && !mRunning) {
return ViewAnimationUtils.createCircularReveal(mRevealInfo.getTarget(),
mRevealInfo.centerX, mRevealInfo.centerY,
mRevealInfo.endRadius, mRevealInfo.startRadius);
}
return null;
}
#Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if(mRunning && child == mRevealInfo.getTarget()){
final int state = canvas.save();
mRevealPath.reset();
mRevealPath.addCircle(mRevealInfo.centerX, mRevealInfo.centerY, mRadius, Path.Direction.CW);
canvas.clipPath(mRevealPath);
boolean isInvalided = super.drawChild(canvas, child, drawingTime);
canvas.restoreToCount(state);
return isInvalided;
}
return super.drawChild(canvas, child, drawingTime);
}
}
For some reason my custom viewgroup is not showing all children when i add weight to my Horizontalscrollview but it works perfect when i removed the weight here is my xml. Does anyone have any idea what is going on?
XML
<?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="match_parent"
android:orientation="vertical">
<LinearLayout
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="7"
android:orientation="vertical">
</LinearLayout>
<HorizontalScrollView
android:id="#+id/handScrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_weight="2"
android:background="#color/colorAccent">
<com.example.example.cardgame.bin.template.HandViewLayout
android:id="#+id/handView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/black_grey">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/cardview_light_background"
android:text="View1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/cardview_dark_background"
android:text="View2" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/face_down"
android:text="View3" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#color/colorAccent"
android:text="View4" />
</com.example.example.cardgame.bin.template.HandViewLayout>
</HorizontalScrollView>
</LinearLayout>
</LinearLayout>
However when i set my Horizontal scrollview to wrap_content or match_parent, it works as desired, why is it not working when i set weight attribute?
Here is my Class HandViewLayout
public class HandViewLayout extends ViewGroup {
private int mLeftWidth;
public float coverCard = 0;
private int mRightWidth;
private final Rect mTmpContainerRect = new Rect();
private final Rect mTmpChildRect = new Rect();
public OnClickListenerViewGroup onClickListenerViewGroup;
public HandViewLayout(Context context) {
super(context);
setHorizontalScrollBarEnabled(true);
setVerticalScrollBarEnabled(true);
}
public void setCoverCard(float coverCard) {
this.coverCard = -Math.abs(coverCard);
}
public float getCoverCard() {
return this.coverCard;
}
public HandViewLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HandViewLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setOnClickListenerViewGroup(OnClickListenerViewGroup onClickListenerViewGroup) {
this.onClickListenerViewGroup = onClickListenerViewGroup;
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
// These are the far left and right edges in which we are performing layout.
int leftPos = getPaddingLeft();
int rightPos = r - l - getPaddingRight();
// This is the middle region inside of the gutter.
final int middleLeft = leftPos + mLeftWidth;
final int middleRight = rightPos - mRightWidth;
// These are the top and bottom edges in which we are performing layout.
final int parentTop = getPaddingTop();
final int parentBottom = b - t - getPaddingBottom();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
final int index = i;
child.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onClickListenerViewGroup.onClickListenerViewGroup(index);
}
});
if (i > 0) {
final View previousChild = getChildAt(i - 1);
mTmpContainerRect.left = middleLeft + lp.leftMargin + previousChild.getLeft() + previousChild.getWidth() + (int) coverCard;
mTmpContainerRect.right = middleRight - lp.rightMargin;
mTmpContainerRect.top = parentTop + lp.topMargin;
mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;
} else {
mTmpContainerRect.left = middleLeft + lp.leftMargin;
mTmpContainerRect.right = middleRight - lp.rightMargin;
mTmpContainerRect.top = parentTop + lp.topMargin;
mTmpContainerRect.bottom = parentBottom - lp.bottomMargin;
}
// Use the child's gravity and size to determine its final
// frame within its container.
Gravity.apply(lp.gravity, width, height, mTmpContainerRect, mTmpChildRect);
// Place the child.
child.layout(mTmpChildRect.left, mTmpChildRect.top,
mTmpChildRect.right, mTmpChildRect.bottom);
}
}
#Override
protected boolean awakenScrollBars() {
return true;
}
#Override
protected int computeVerticalScrollExtent() {
return super.computeVerticalScrollExtent();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
mLeftWidth = 0;
mRightWidth = 0;
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
// Log.e("child Text", i + ": " + ((TextView) child).getText().toString());
if (child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
// last one show all
if (i == getChildCount() - 1) {
maxWidth += child.getMeasuredWidth();
} else {
maxWidth += child.getMeasuredWidth() + coverCard;
}
Log.d("Spacer", "spacer, " + i + "," + maxWidth);
maxHeight = Math.max(maxHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
}
}
setMeasuredDimension(resolveSizeAndState(maxWidth, heightMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState));
}
#Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new HandViewLayout.LayoutParams(getContext(), attrs);
}
#Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}
#Override
protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}
#Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof LayoutParams;
}
#Override
public boolean shouldDelayChildPressedState() {
return false;
}
public static class LayoutParams extends MarginLayoutParams {
public int gravity = Gravity.TOP | Gravity.START;
public static int POSITION_MIDDLE = 0;
public static int POSITION_LEFT = 1;
public static int POSITION_RIGHT = 2;
public int position = POSITION_MIDDLE;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray atts = c.obtainStyledAttributes(attrs, R.styleable.HandViewLayout);
gravity = atts.getInt(R.styleable.HandViewLayout_android_layout_gravity, gravity);
position = atts.getInt(R.styleable.HandViewLayout_layout_position, position);
atts.recycle();
}
public LayoutParams(int width, int height) {
super(width, height);
}
public LayoutParams(MarginLayoutParams source) {
super(source);
}
public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}
}
}
Attributes xml
<declare-styleable name="HandViewLayout">
<attr name="layoutColor" format="color" />
<attr name="android:layout_gravity" />
<attr name="layout_position">
<enum name="middle" value="0" />
<enum name="left" value="1" />
<enum name="right" value="2" />
</attr>
</declare-styleable>
PIC
I dont know to add more listview inside one page layout (attach picture)
I want Each ListView is not scrolling. Page layout is scrolling only.
Help me!!
Build same home layout app: https://play.google.com/store/apps/details?id=com.google.android.youtube
Answer
I had resolve this problem
Step1: Make new file java:
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;
}
}
Step2: Java: Replace all ListView ->ExpandableHeightListview, and set listview.setExpanded(true);
Step3: layout xml: Replace
<yourpackage.ExpandableHeightListview
android:id="#+id/etResponse"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="300dp"
android:scrollbars="none"
android:orientation="vertical"
android:fadingEdge="none">
</yourpackage.ExpandableHeightListview>
Step4: Done!
You can calculate height of listview belong to number item in this. Here is example :
public class ExpandedListView extends ListView {
private android.view.ViewGroup.LayoutParams params;
private int old_count = 0;
public ExpandedListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onDraw(Canvas canvas) {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
if (getChildAt(0)!= null){
params.height = getCount() * (old_count > 0 ? (getChildAt(0).getHeight()) : 0) ;
}else
params.height = 0;
setLayoutParams(params);
requestLayout();
}
super.onDraw(canvas);
}
}
And use it in xml like this :
.......
<your package.ExpandedListView
android:id="#+id/lv1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
<your package.ExpandedListView
android:id="#+id/lv2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none" />
....
Note This solution will fix the height of listView.
You need to set the height of each ListView. Lets say 30dp also give layout_weight="1" Here is example LinearLayout nested inside ScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout 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"
android:orientation="vertical">
<ListView
android:id="#+id/lastest"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
<ListView
android:id="#+id/featured"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
<ListView
android:id="#+id/startup"
android:layout_marginTop="10sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="30dp" />
</LinearLayout>
</ScrollView>
Hope it helps
Please use 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;
}
}
in .xml file:
<yourpackagename.ExpandableHeightListview
android:id="#+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/White"
android:scrollbars="none"
android:orientation="vertical"
android:fadingEdge="none">
</cyourpackagename.ExpandableHeightListview>
I have following code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 1"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 2"
android:textSize="24sp" />
</LinearLayout>
that results:
How can I have equal size of View's height with its width (that is resulted by layout_weight)?
You have to override the onMeasure method set the same height as the height. Please see this question: Simple way to do dynamic but square layout
This is the complete solution that I come up with:
SquareLinearLayout.java :
public class SquareLinearLayout extends LinearLayout {
public SquareLinearLayout(Context context) {
super(context);
}
public SquareLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthDesc = MeasureSpec.getMode(widthMeasureSpec);
int heightDesc = MeasureSpec.getMode(heightMeasureSpec);
int size = 0;
if (widthDesc == MeasureSpec.UNSPECIFIED
&& heightDesc == MeasureSpec.UNSPECIFIED) {
size = getContext().getResources().getDimensionPixelSize(R.dimen.default_size); // Use your own default size, for example 125dp
} else if ((widthDesc == MeasureSpec.UNSPECIFIED || heightDesc == MeasureSpec.UNSPECIFIED)
&& !(widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED)) {
//Only one of the dimensions has been specified so we choose the dimension that has a value (in the case of unspecified, the value assigned is 0)
size = width > height ? width : height;
} else {
//In all other cases both dimensions have been specified so we choose the smaller of the two
size = width > height ? height : width;
}
setMeasuredDimension(size, size);
}
}
activity_my.xml :
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:listitem="#layout/item"
tools:context=".MyActivity">
</ListView>
item.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.appsrise.squarelinearlayout.SquareLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#android:color/holo_blue_bright">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 1"
android:textSize="24sp" />
</com.appsrise.squarelinearlayout.SquareLinearLayout>
<com.appsrise.squarelinearlayout.SquareLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#android:color/holo_green_light">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 2"
android:textSize="24sp" />
</com.appsrise.squarelinearlayout.SquareLinearLayout>
</LinearLayout>
MyActivity.java :
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(new BaseAdapter() {
private LayoutInflater mInflater = LayoutInflater.from(MyActivity.this);
#Override
public int getCount() {
return 100;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null)
convertView = mInflater.inflate(R.layout.item, parent, false);
return convertView;
}
});
}
}
Simpler solution is to pass the width measurement specification into the height specification when calling onMeasure (or the other way around if you want the height to determine the square size).
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
public class SquareLinearLayout extends LinearLayout{
public SquareLinearLayout(Context context) {
super(context);
}
public SquareLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareLinearLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
// or super.onMeasure(heightMeasureSpec, heightMeasureSpec);
}
}
Xamarin version
[Register("SquareFrameLayout")]
public class SquareFrameLayout : LinearLayout
{
public SquareFrameLayout(Context context) : base(context)
{
}
public SquareFrameLayout(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public SquareFrameLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
var width = MeasureSpec.GetSize(widthMeasureSpec);
var height = MeasureSpec.GetSize(heightMeasureSpec);
var widthDesc = MeasureSpec.GetMode(widthMeasureSpec);
var heightDesc = MeasureSpec.GetMode(heightMeasureSpec);
if (widthDesc == MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
{
//size = Context.Resources.GetDimensionPixelSize(Resource.Dimension.default_size); // Use your own default size, for example 125dp
height = width = 0;
}
else if(heightDesc != MeasureSpecMode.Unspecified && widthDesc == MeasureSpecMode.Unspecified)
{
width = height;
}
else if (widthDesc != MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
{
height = width;
}
else
{
//In all other cases both dimensions have been specified so we choose the smaller of the two
var size = width > height ? height : width;
width = height = size;
}
SetMeasuredDimension(width, height);
}
and
[Register("SquareLinearLayout")]
public class SquareLinearLayout : LinearLayout
{
public SquareLinearLayout(Context context) : base(context)
{
}
public SquareLinearLayout(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public SquareLinearLayout(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
base.OnMeasure(widthMeasureSpec, heightMeasureSpec);
var width = MeasureSpec.GetSize(widthMeasureSpec);
var height = MeasureSpec.GetSize(heightMeasureSpec);
var widthDesc = MeasureSpec.GetMode(widthMeasureSpec);
var heightDesc = MeasureSpec.GetMode(heightMeasureSpec);
if (widthDesc == MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
{
//size = Context.Resources.GetDimensionPixelSize(Resource.Dimension.default_size); // Use your own default size, for example 125dp
height = width = 0;
}
else if(heightDesc != MeasureSpecMode.Unspecified && widthDesc == MeasureSpecMode.Unspecified)
{
width = height;
}
else if (widthDesc != MeasureSpecMode.Unspecified && heightDesc == MeasureSpecMode.Unspecified)
{
height = width;
}
else
{
//In all other cases both dimensions have been specified so we choose the smaller of the two
var size = width > height ? height : width;
width = height = size;
}
SetMeasuredDimension(width, height);
}
}
You can do this also, If you need only one TextView needs to be square :
ViewTreeObserver vto = textview.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
textview.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int width = textview.getMeasuredWidth();
int height = textview.getMeasuredHeight();
ViewGroup.LayoutParams params = textview.getLayoutParams();
if (width > height)
params.height = width;
else
params.width = height;
textview.setLayoutParams(params);
}
});
You can divide a LinearLayout into two equal LinearLayout like this..
<LinearLayout android:orientation="horizontal" android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:layout_weight="1" android:layout_height="fill_parent" android:layout_width="fill_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 1"
android:textSize="24sp" />
</LinearLayout>
<LinearLayout android:layout_weight="1" android:layout_height="fill_parent" android:layout_width="fill_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Test 1"
android:textSize="24sp" />
</LinearLayout>
</LinearLayout>
This will divide the LinearLayout into two equal LinearLayouts and each of these LinearLayouts will contain the TextViews