I want to customize a layout and make it into a square. In xml, I set the its layout_width and layout_height into 'match_parent'. And then in its onMeasure() method, I get the values of its height and width and set the shortest of them as the value of each side of square. The code is kind of like this:
<SquaredRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
/>
public class SquaredRelativeLayout extends RelativeLayout {
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if(width > height) {
super.onMeasure(heightMeasureSpec, heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}
}
}
Now here is my problem: I need to set this layout center horizontally of its parent. But every time when width > height, the layout will be aligned to left of its parent. Does any one how to solve this?
Use android:gravity="center" in your SquaredRelativeLayout's parent
or
use android:layout_centerInParent="true" in your SquaredRelativeLayout (instead of android:layout_centerHorizontal="true")
Use android:gravity="center" in your parent layout.
Related
I need a view (custom view called DayView) that stretches twice the height of the scrollView it's in. In this view, there are two nested views, one of which is another custom view. The custom views all extend from RelativeLayout.
The layout is like this:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Is twice the size as scrollView, see code below -->
<com.example.DayView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Should be same size as parent DayView -->
<include layout="#layout/layout_dayplan_background"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!-- Should be same size as parent DayView -->
<com.example.BlockView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.example.DayView>
</ScrollView>
The two nested views (include and BlockView) should have the same height as the parent DayView.
In the DayView, I override the onMeasure to make it twice as large. This works: (see the '* 2' in the second to last row)
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth, parentHeight);
this.setLayoutParams(new ScrollView.LayoutParams(parentWidth, parentHeight * 2 ));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
The DayView has the correct size, however, the two nested views don't strech along with the parent, but seem to use a wrap_content height layout rule.
Question
How can I make these two nested views take over the same height as the parent DayView?
You can try following methods
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec) * 2;
this.setMeasuredDimension(parentWidth, parentHeight);
measureChildren(MeasureSpec.makeMeasureSpec(parentWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(parentHeight, MeasureSpec.EXACTLY));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Here it is measuring children too. Maybe this can work
I have a custom view with Yellow background. I plan to add a Red background TextView, with match_parent for both width and height on it. Here's what I had done.
MainActivity.java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LinearLayout mainView = (LinearLayout)this.findViewById(R.id.screen_main);
RateAppBanner rateAppBanner = new RateAppBanner(this);
mainView.addView(rateAppBanner);
}
}
RateAppBanner.java
public class RateAppBanner extends LinearLayout {
public RateAppBanner(Context context) {
super(context);
setOrientation(HORIZONTAL);
LayoutInflater.from(context).inflate(R.layout.rate_app_banner, this, true);
this.setBackgroundColor(Color.YELLOW);
}
}
rate_app_banner.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="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#ffffffff"
android:background="#ffff0000"
android:text="Hello World" />
</LinearLayout>
Now, I would like to have a fixed width & height custom view. I realize, after I'm having fixed width & height custom view, the added TextView doesn't obey match_parent attribute.
Here's the change I had done on custom view.
RateAppBanner.java
public class RateAppBanner extends LinearLayout {
...
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = 320;
int desiredHeight = 50;
desiredWidth = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, desiredWidth, getResources().getDisplayMetrics());
desiredHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, desiredHeight, getResources().getDisplayMetrics());
super.onMeasure(desiredWidth, desiredHeight);
//MUST CALL THIS
setMeasuredDimension(desiredWidth, desiredHeight);
}
I realize the added TextView doesn't match_parent anymore!
Now, we can see the Yellow custom view is having fixed size 320x50. I expect the Red TextView will fill up the entire custom view due to match_parent attribute.
However, that's not the case. I believe my implementation for custom view's onMeasure isn't correct. May I know what is the correct way to fix this?
The complete source code can be downloaded from abc.zip
After lots of trial and error and doing research work, final found answer.
You have set measurements for layout but not for child view, so for that you need to put this in onMeasure method,
super.onMeasure(
MeasureSpec.makeMeasureSpec(desiredWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(desiredHeight, MeasureSpec.EXACTLY));
Reference link : Inflated children of custom LinearLayout don't show when overriding onMeasure
And finally it's working :)
I have put a TextView inside a ScrollView in Android:
<ScrollView
android:layout_width = "fill_parent"
android:layout_height = "wrap_content">
<TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content" />
</ScrollView>
With this configuration, the scrollview grows to wrap the textview-content.
How can I achieve that the scrollview takes only as much space as needed (for few text), but at the same time limit the size to 100dp (for long texts) ?
If I set layout_height to 100dp, a lot of space is wasted when the text is short
If I set layout_height to wrap_content, the scrollview runs the risk to fill the whole screen, but I don't want the whole sreen to only contain this scrollview. It should be 100dp heigh as a maximum.
The solution which was found:
Thank you for alls answers. For all people that have the same issue, here goes the accepted solution:
Create a custom ScrollView class an use this class inside your xml file instead ScrollView. Then override onMeasure() method:
public class ScrollMyVew extends ScrollView {
public static final int maxHeight = 100; // 100dp
// default constructors
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(dpToPx(getResources(),maxHeight), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private int dpToPx(Resources res, int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
}
}
This solution is taken from https://stackoverflow.com/a/23617530/3080611
Try something like this:
<ScrollView
android:id="#+id/myScrollView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"/>
<TextView
android:id="#+id/myTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxHeight="your_value_here"/>
</ScrollView>
Dynamically change the size of the TextView if the number of characters exceeds a certain amount.
Ex:
TextView v = (TextView) findViewById(R.id.sometext);
LayoutParams lp = v.getLayoutParams();
lp.height = 50;
v.setLayoutParams(lp);
I have created a custom layout which extends RelativeLayout. At the moment, this layout does nothing except overriding the onMeasure method (that I will need later). Here is my code:
public class CustomLayout extends RelativeLayout {
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
}
And I have the following layout file:
<LinearLayout
android:id="#+id/containerLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal" >
<...CustomLayout
android:id="#+id/item"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="50"
android:background="#fff" >
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Hello"
android:textSize="20sp" />
</...CustomLayout>
<RelativeLayout
android:id="#+id/controls"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="50"
android:background="#0f0" >
</RelativeLayout>
</LinearLayout>
The problem is that the height is null. During my debugging, I have noticed that if I change the CustomLayout to a RelativeLayout it works.
So, it is quite obvious that the problem comes from my CustomLayout, but what do I need to add to make the wrap_content work ?
I have finally found the problem. I change this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
To this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
And it works fine.
Explanation
First, the following line was useless:
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
But why does it makes the View's height null?
In fact, I misunderstood the paramaters of the onMeasure method. They are MeasureSpec values. Here is what Google says about this object:
A MeasureSpec encapsulates the layout requirements passed from parent
to child. Each MeasureSpec represents a requirement for either the
width or the height. A MeasureSpec is comprised of a size and a mode.
There are three possible modes:
UNSPECIFIED The parent has not imposed any constraint on the child. It
can be whatever size it wants. EXACTLY The parent has determined an
exact size for the child. The child is going to be given those bounds
regardless of how big it wants to be. AT_MOST The child can be as
large as it wants up to the specified size. MeasureSpecs are
implemented as ints to reduce object allocation. This class is
provided to pack and unpack the tuple into the int
The widthMeasureSpec and heightMeasureSpec values are not only the width and the height of the View. In this case, passing these values to setMeasureDimension are completly wrong because this method actually requires real sizes as parameters.
i have 2 separate custom view in 1 activity.
i have 2 question:
1- how can i do this(put 2 view side by side)?
2- and how can i put second view in second half of the display it means how to make view to consider (width/2,0) instead of (0,0) to start ??
note: the height of my views is the height of display and width of my views is width/2 of display's width.
i set the onMeasure() method like this
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = widthMeasureSpec/2;
int measuredHeight = heightMeasureSpec;
setMeasuredDimension(measuredWidth,measuredHeight );
}
Try adding both views inside a LinearLayout horizontal oriented, both with weight=1. It would look something like.-
<LinearLayout
android:width="match_parent"
android:height="wrap_content"
android:orientation="horizontal">
<YourCustomView1
android:width="wrap_content"
android:height="wrap_content"
android:weight="1" />
<YourCustomView2
android:width="wrap_content"
android:height="wrap_content"
android:weight="1" />
</LinearLayout>