How to correctly resize children of customview - android

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

Related

Custom view android onMeasure method shows double the value set in layout

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;

How to create a square layout and set it center horizontally

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.

Custom ViewPager inside ObservableScrollView not measuring Height Properly

I have a CustomViewPager inside an ObservableScrollView which looks like this:
It seems to measure the fragment but does not measure the height of the fragment which is off the screen. So I can't actually scroll up.
This is the code for the CustomViewPager:
public class CustomViewPager extends ViewPager {
private View view;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
View tab = getChildAt(getCurrentItem());
int width = getMeasuredWidth();
int tabHeight = tab.getMeasuredHeight();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
NOTE: If I add say + 1000 to heightMeasureSpec in super.onMeasure(widthMeasureSpec, heightMeasureSpec); then I can scroll the size of the fragment as well as any extra space. But obviously this is not a preferred solution.
Here is my XML file:
<FrameLayout 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">
<LinearLayout
android:id="#+id/infoBox"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="240dp">
<!-- Code for other views -->
</LinearLayout>
<com.github.ksoichiro.android.observablescrollview.ObservableScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="266dp"
android:orientation="vertical">
<com.ui.customviewpager.CustomViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</com.github.ksoichiro.android.observablescrollview.ObservableScrollView>
What seems to be the issue here? It seems like I am not the only one with this issue.
I implemented some of this design from this link here
ScrollView child should not have margin for the scrollView to display properly.
It seems that the margin is not taken into account when the scrollView measure its child.
Try removing margin of LinearLayout (you can use padding to reproduce the effect).
Why dont you use ObservableScrollView inside the fragment and put the viewpager inside a TouchInterceptionFrameLayout (from the same lib), then set setTouchInterceptionViewGroup of the ObservableScrollView to be the one containing your viewpager and do the logic on the TouchInterceptionListener in your activity to either move it up and down with with animation in order to mimic a smooth scrolling effect.
I hope that is that your are looking for to achieve and hopefully it will help you.
Ps: See the guy example app and source (Link), it is a bit complex but im sure you will find something.
Hello i am not much aware of ObservableScrollView but according to your problem you are not able to find out height of fragment. After searching a lot i am able to find out tutorial to get the height of fragments.
here is the link
http://adanware.blogspot.in/2012/06/android-getting-measuring-fragment.html
Hope, this will help you.

wrap_content does not work with custom RelativeLayout

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.

How can I make an android ViewGroup and all its child Views dynamically maintain equal width based on the widest child?

I want my android layout to behave like so:
Suppose SomeLayout is a parent of Widget1, Layout2, and Widget2, which are displayed in that order from top to bottom, like so:
|-------SomeLayout-------|
||--------Widget1-------||
||______________________||
||--------Layout2-------||
||______________________||
||--------Widget2-------||
||______________________||
|________________________|
The 3 children have content that is changing. Dynamically as they change, I always want the one with the widest content to wrap to content. I want SomeLayout to wrap around that widest child, and I want all other children to match that widest one. Even if which one is widest changes.
I have been trying for some time to accomplish this using more methods than I can count. All failures. Does anyone know haw to achieve this effect via the android layout XML? I would be willing to use a Java programmatic solution if that's all that anyone can provide, but I would prefer to do it via just the XML.
Good Question buddy.
After started checking I felt this was a good question..
Here is what you want.. Check it out..
Its just simple one..
Apply some layout width to wrap_content and all direct child's width to match_parent..
see the example below.. you can conform it assigining the background color.
<?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" >
<!-- This is Your Some Layout -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- Widget1 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2431234vb sset " />
<!-- Your Layout 2 (inner one) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2431234v " />
</LinearLayout>
<!-- Widget2 -->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2431234vb sset " />
</LinearLayout>
</LinearLayout>
Hope It will help you..
I hope your SomeLayout extends ViewGroup, so I'd try to override onMeasure method in order to measure all the childs in a proper way.
For example
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int specWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxWidth = 0;
int maxIndex = 0;
for (int i = 0; i < getChildCount(); i++){
View child = getChildAt(i);
final int widthSpec = MeasureSpec.makeMeasureSpec(
specWidth, MeasureSpec.UNSPECIFIED);
final int heightSpec = MeasureSpec.makeMeasureSpec(
0, MeasureSpec.UNSPECIFIED);
child.measure(widthSpec, heightSpec);
int width = child.getMeasuredWidth();
if (width > maxWidth){
maxWidth = width;
maxIndex = i;
}
}
for (int i = 0; i < getChildCount(); i++){
if (i != maxIndex){
View child = getChildAt(i);
final int widthSpec = MeasureSpec.makeMeasureSpec(
maxWidth, MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(
0, MeasureSpec.UNSPECIFIED);
child.measure(widthSpec, heightSpec);
}
}
setMeasuredDimension(someMeasuredWidth, someMeasuredHeight);
}
So you should define the widest child and measure all the others in order to adjust maximum size. After that you should layout all the childs in onLayout method implementation according measured dimensions.
Hope it will help you

Categories

Resources