what I want to do in a view is have a textview and to the right of it, have another custom view X with the same height as the textview and have width=height:
+---------------------+---+
|A flexible string | X |
+---------------------+---+
My attempt so far is:
Inside the X class:
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(height,height);
Log.v("measure","width:"+height + " height:"+height);
}
and my xml:
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:id="#+id/mytext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"/>
<mystuff.X
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_toRightOf="#id/mytext"/>
</RelativeLayout>
The log statement prints out:
width:1073741823 height:1073741823
width:37 height:37
width:1073741823 height:1073741823
width:37 height:37
width:1073741823 height:1073741823
width:37 height:37
when the view is created and it fills the width of the screen:
+---------------------+-----------------+
|A flexible string | X |
+---------------------+-----------------+
I would greatly appreciate any help with this.
Thanks!
Ian
You are treating the measure specs as actual pixels. They are in fact the ints that represent "fill_parent", "wrap_content", etc.
What you want to do is:
#Override
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) {
int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(height,height);
Log.v("measure","width:"+height + " height:"+height);
}
Related
I believe my problem is related to this: widthMeasureSpec is 0 when in HorizontalScrollView
Long story short, I'm trying to create a custom horizontal scroll view. At some point, I'm overriding
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
And while this works fine in Android >= 7, I'm getting a value of 0 for widthMeasureSpec in Android <= 6.
The code for measureChild changed between API 23 and 24:
In API 23:
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
In API 24:
final int childWidthMeasureSpec = MeasureSpec.makeSafeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - horizontalPadding),
MeasureSpec.UNSPECIFIED);
I have tried to get the width from the parent view using a getter, but it is not working as expected as only some calls get the correct width. I also tried to override measureChild in the parent and putting the newest code there, with no luck:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChild(getTouchInterceptTextView(), widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void measureChild(View child, int parentWidthMeasureSpec,
int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
final int horizontalPadding = getPaddingLeft() + getPaddingRight();
final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
Math.max(0, MeasureSpec.getSize(parentWidthMeasureSpec) - horizontalPadding),
MeasureSpec.UNSPECIFIED);
final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
getPaddingTop() + getPaddingBottom(), lp.height);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
My wholes files are here: https://github.com/AdrienPoupa/VinylMusicPlayer/commit/ba0dfae7dd03771f3625b8393927986aad552e2a
The important part being:
<com.poupa.vinylmusicplayer.views.TouchInterceptHorizontalScrollView
android:id="#+id/title_scrollview"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.poupa.vinylmusicplayer.views.AutoTruncateTextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif"
android:textAppearance="#style/TextAppearance.AppCompat.Subhead" />
</com.poupa.vinylmusicplayer.views.TouchInterceptHorizontalScrollView>
The onMeasure function is in AutoTruncateTextView. I can get the measures in TouchInterceptHorizontalScrollView but that does not seem to help. I tried to add android:fillViewport="true" in the XML for TouchInterceptHorizontalScrollView, AutoTruncateTextView and both but it did not change the calculation.
What can I do to get the proper value of widthMeasureSpec in Android 6 and below?
Thanks for your help!
After many tries, it seems to be working by adding the following snippet to AutoTruncateTextView's onMeasure:
if (textBoundsWidth == 0) {
textBoundsWidth = getTouchInterceptFrameLayout().getMeasuredWidth();
}
Basically, getting the width of the TouchInterceptFrameLayout, that is the 2nd level of the XML file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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="72dp"
android:foreground="?attr/rectSelector"
tools:ignore="UnusedAttribute">
<!-- for getSwipeableContainerView() -->
<com.poupa.vinylmusicplayer.views.TouchInterceptFrameLayout
android:id="#+id/dummy_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
and keeping the code posted above otherwise the truncate mechanism does not work anymore.
I am trying to create own custom view ,I observed onMeasure shows into 2 of whatever value set.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.customview.PercentageCircle
android:layout_width="match_parent"
android:layout_height="100dp"
custom:currentValue="0"
custom:maxValue="100"
custom:thickNess="80"
custom:fillBackgroundColor="#color/light_gray"
custom:fillColor="#color/red"
/>
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);//shows 200
this.setMeasuredDimension(parentWidth, parentHeight);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
When I log the parentHeight or parentWidth ,I get double the specified value.I am not able to understand cause of it.
All the inputs to Canvas functions are in pixels.
Function parameters of onMeasure are also in pixels.
To work UI across the devices , If we use pixels, things become too small on high resolution screens.
To convert from dp to pixels,
float heightInPixel = getHeight()/ getResources().getDisplayMetrics().density;
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.
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 created a custom View, and I put this on a LinearLayout.
Problem is that I cannot fill completely the height of the layout, the size of the custom View is always squared, width = height.
Here is my layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:layout_weight="0">
<it.inav.graphics.MapView
android:id="#+id/map"
android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"/>
</LinearLayout>
The only way it seems to work is using a RelativeLayout and "strecth" the view using both
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
but still, if I try to get the size height, it returns the same length of before.
The problem was in the definition of the View, and not in the XML.
I have done copy-paste of this piece of code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
int d = Math.min(measuredWidth, measuredHeight);
setMeasuredDimension(d, d);
}
And, naturally, it sets the size of the View as a square with the length of the minor.
This is the correct code:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = measure(widthMeasureSpec);
int measuredHeight = measure(heightMeasureSpec);
setMeasuredDimension(measuredWidth, measuredHeight);
}