Constraint Layout "wrap_content" with dimensionRatio child view - android

In ConstraintLayout version < beta5, I had layouts like this example below:
<android.support.constraint.ConstraintLayout
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="wrap_content">
<ImageView
android:id="#+id/square_image"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="H, 1:1"/>
</android.support.constraint.ConstraintLayout>
However, versions starting beta5 have removed the MATCH_PARENT constraint for child views.
The documentation gives examples of using app:layout_constraintDimensionRatio:
You can also use ratio if both dimensions are set to MATCH_CONSTRAINT
(0dp). In this case the system sets the largest dimensions the
satisfies all constraints and maintains the aspect ratio specified. To
constrain one specific side based on the dimensions of another. You
can pre append W," or H, to constrain the width or height
respectively. For example, If one dimension is constrained by two
targets (e.g. width is 0dp and centered on parent) you can indicate
which side should be constrained, by adding the letter W (for
constraining the width) or H (for constraining the height) in front of
the ratio, separated by a comma:
<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html#DimensionConstraints
This example works when the parent layout has a fixed height or match_parent, but not when the parent is set to wrap_content.
Using my code example above, if I set the ImageView width to 0dp, the parent view collapses as if it has no content.
This was an incredibly useful feature, I feel like I'm just missing something in this new version. Any help appreciated.

ConstraintLayout v1.0.2 fixes this issue.

Related

what is the total pixel of match parent of screen in android?

Suppose if I am setting a horizontal orientation linear layout then what should be the total pixel of match parent so that I could adjust my buttons and text view according to that size.
I tried to place all margins and calculate...
the expected output would depend on screen size.
total pixels for match_parent of a view is depend on your parentView type, dimensions and composition of views within the layout, for example if your parentView is LinearLayout of size 100px * 100px then your match_parent for a view within that LinearLayout is 100px * 100px (iff you have only one view within that LinearLayout otherwise it depends on your composition) you can get your view's height and width (in pixels) programmatically to by using below code to any view or Layout
Java
view.post(new Runnable(){
#Override
public void run() {
int height = view.getMeasuredHeight();
int width = view.getMeasuredWidth();
}
});
kotlin
view.post {
val width = view.measuredWidth
val height = view.measuredHeight
}
after getting height and width of layout you can manage you margin or size according to your logic
The total pixels of match parent is the total pixels of the screen size, and if you to implement an auto resize for your views you should either use constraint layoutas a parent layout for your views, either use this great library that uses a new size unit called sdp https://github.com/intuit/sdp
Don't user pixels, it makes your screen not responsive to all screen sizes. use ConstraintLayout or Relative Layout if you want your screen to be responsive to all screen sizes.
Here is an example of a view that his width is qeual to all of the screen size using ConstraintLayout :
<androidx.constraintlayout.widget.ConstraintLayout 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"
>
<Button
android:id="#+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Use ratio for ImageView size with ConstrainLayout for Responsiveness

I'm using ConstraintLayout to make my app responsive to different screen size.
I want to use ratio to size my widgets.
So to use ratio I have to set my width and height to match_constraints.
So what I'm doing is :
<ImageView
android:id="#+id/my_img"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="150dp"
android:layout_marginStart="250dp"
android:layout_marginTop="5dp"
android:adjustViewBounds="true"
android:src="#drawable/img_test"
app:layout_constraintBottom_toTopOf="#+id/bot_img"
app:layout_constraintDimensionRatio="h,125:50"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/top_img" />
So I will use margins and ratios,in dp, to set up my img size.
The problem is that when I'm using different screen size, my img will not keep the exact ratio I want.
Can you help me ? Am I using ConstraintLayout right ? Thanks a lot
I think you misunderstood the use of constraintDimensionRatio. Set your both horizontal constraints with width="0dp" as well as set constraintDimensionRatio (like 1:1). And set only one vertical constraint (like top) with height="0dp" and leave the other one (or vice-versa depending on your requirement). Now your view's width will expand as much as it can and height will adjust to the ratio. See below example for better understanding.
<ImageView
android:id="#+id/my_img"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
android:src="#drawable/img_test"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
Above code will result into a square image which will scale itself for different parent widths.
Happy codding :)

ConstraintLayout Guideline expanding together with view

I got this setup:
<ScrollView 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"
android:fillViewport="true">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="#+id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.Guideline
android:id="#+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.35" />
...
</android.support.constraint.ConstraintLayout>
</ScrollView>
Now when the view is not full and has no need for a scroll bar - everything works as expected - the image is 35% in relation to the screen size. But as more content appears under the image, a need for scroll bar appears and the guideline's constraintGuide of 0.35 percent seems to be calculated off whole length of the screen (not physical), so the ImageView also becomes bigger as the view becomes "longer".
Is there a way to avoid this and always have x percent of physical screen size?
The guideline you have specified is placed at a percentage distance from the top of the ConstraintLayout. Unfortunately, for your application, the guideline is tied to the overall height of the view and not a percentage of the screen. So, if the ConstraintLayout is taller than the screen size allocated to it, you will see the shift. See documentation for Guideline.
Positioning a Guideline is possible in three different ways:
specifying a fixed distance from the left or the top of a layout (layout_constraintGuide_begin)
specifying a fixed distance from the right or the bottom of a layout (layout_constraintGuide_end)
specifying a percentage of the width or the height of a layout (layout_constraintGuide_percent)
You can specify a static offset from the top of the layout in terms of dp, but this will not accommodate different screen sizes. I don't believe there is a solution just using XML.
You can, however, calculate the number of pixels in code and set the distance on a run-time basis. You would need to change the Guideline to one that is a fixed distance from the top of the layout, calculate the distance from the top, and call setGuidelineBegin to place the guideline.
setGuidelineBegin
void setGuidelineBegin (int guidelineID,
int margin)
Set the guideline's distance form the top or left edge.

Resize parent to match its child

I have a complex xml layout with part of it being:
...
<FrameLayout
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_weight="1" >
<ImageView
android:id="#+id/flexible_imageview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#drawable/gradient"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingTop="8dp" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</FrameLayout>
...
The height of the FrameLayout #+id/parent must be determined at runtime because it is displayed above many other views, and they must be shown in the layout. This way the FrameLayout fills the remaining space perfectly (using height="0dp" and weight="1" properties).
The ImageView #+id/flexible_imageview receives an image from the network, and it always shows with the correct aspect ratio. This part is already ok as well. This View is the largest and should determine the size of the FrameLayout #+id/parent.
The problem is that when the image is drawn, the width of the FrameLayout #+id/parent is not adjusted to wrap and be the ImageView #+id/flexible_imageview as it should be.
Any help is appreciated.
-- update --
I've updated the layout to clarify some of the missing parts, and to add the reasoning behind all of it.
What I want is to have an Image (ImageView #+id/flexible_imageview) with unknown dimensions to have, on top of it, a gradient and some text on top of the gradient. I can't set the FrameLayout #+id/parent dimensions to both wrap_content because there is more Views after this Image that must be shown. If there's not enough space in the layout, the Image (ImageView #+id/flexible_imageview) is reduced until it all fits in the layout, but it should maintain its aspect ratio, and the gradient/texts on top of it.
The #drawable/gradient is just:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<gradient
android:angle="270"
android:endColor="#aa000000"
android:startColor="#00000000" />
</shape>
-- update 2 --
I added two images below to demonstrate what's happening, and what should happen:
Bug:
Correct:
If would help if you explained more about what you are trying to accomplish in your layout (not the layout itself but what should the user see on the screen and what are the other elements in the layout).
A FrameLayout with multiple children is usually a "code smell". Usually, FrameLayouts should have only one child element. So this makes me wonder whether there is something wrong with your design.
-- Edit --
If I understand correctly, you are trying the framelayout to wrap the content of the image but at the same time match the space left from the other layout views before/after the frame layout.
What is the parent view/layout of the frame layout?
I see a couple of problems with this design or your explanation:
You have framelayout width set to match parent, but you want to wrap the content of the image.
You want the imageView to be reduced but you are not taking into account the text views in the linear layout. You have them set to wrap content. So when the fame layout is small, you will not see all the textviews. (Unless you are resizing them as well somehow).
Sorry if this isn't helpful enough but it's difficult to understand what you are trying to accomplish with this layout. A sample use-case would help in providing you a better recommendation.
When a dimension (width / height) is MeasureSpec.EXACTLY adjustViewBounds will not effect it.
In your case, having android:width="match_parent" ensures that the image view is the size of the parent, regardless of adjustViewBounds.
It works to begin with because the height is wrap_content - the height is adjusted when the image is scaled to fill the width.
When you override the height to fit everything on the screen (this may not be a great idea to begin with), the width is still matching the parent and doesn't get adjusted. However, because the scale type is ScaleType.FIT_CENTER the image is scaled and positioned so that the entirety of it fits in the bounds of the ImageView (and centred.. hence the name).
If you turn on the debug option for drawing layout bounds, or look at your app using hierarchyviewer, you'll see that the image view is still matching the width of its parent.
There are a couple of ways you could do what you want.
Since you're already manually calculating the height, setting the width shouldn't be that hard.
Drawable drawable = imageView.getDrawable();
if (drawable != null && drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) {
int height = // however you calculate it
int width = height / (getDrawable().getIntrinsicHeight() / getDrawable().getIntrinsicWidth());
}
You might also get away with
<ImageView
android:id="#+id/flexible_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:adjustViewBounds="true"
android:minWidth="9999dp" />
Even if this works, you probably wouldn't be able to use it in a horizontal LinearLayout using weights any more (for example, if you wanted a landscape variant of the layout), or a number of other scenarios.

What's the difference between fill_parent and wrap_content?

In Android, when layout out widgets, what's the difference between fill_parent (match_parent in API Level 8 and higher) and wrap_content?
Is there any documentation where you can point to? I'm interested in understanding it very well.
Either attribute can be applied to View's (visual control) horizontal or vertical size. It's used to set a View or Layouts size based on either it's contents or the size of it's parent layout rather than explicitly specifying a dimension.
fill_parent (deprecated and renamed MATCH_PARENT in API Level 8 and higher)
Setting the layout of a widget to fill_parent will force it to expand to take up as much space as is available within the layout element it's been placed in. It's roughly equivalent of setting the dockstyle of a Windows Form Control to Fill.
Setting a top level layout or control to fill_parent will force it to take up the whole screen.
wrap_content
Setting a View's size to wrap_content will force it to expand only far enough to contain the values (or child controls) it contains. For controls -- like text boxes (TextView) or images (ImageView) -- this will wrap the text or image being shown. For layout elements it will resize the layout to fit the controls / layouts added as its children.
It's roughly the equivalent of setting a Windows Form Control's Autosize property to True.
Online Documentation
There's some details in the Android code documentation here.
fill_parent (deprecated) = match_parent
The border of the child view expands to match the border of the parent view.
wrap_content
The border of the child view wraps snugly around its own content.
Here are some images to make things more clear. The green and red are TextViews. The white is a LinearLayout showing through.
Every View (a TextView, an ImageView, a Button, etc.) needs to set the width and the height of the view. In the xml layout file, that might look like this:
android:layout_width="wrap_content"
android:layout_height="match_parent"
Besides setting the width and height to match_parent or wrap_content, you could also set them to some absolute value:
android:layout_width="100dp"
android:layout_height="200dp"
Generally that is not as good, though, because it is not as flexible for different sized devices. After you have understood wrap_content and match_parent, the next thing to learn is layout_weight.
See also
What does android:layout_weight mean?
Difference between a View's Padding and Margin
Gravity vs layout_gravity
XML for above images
Vertical LinearLayout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="width=wrap height=wrap"
android:background="#c5e1b0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="width=match height=wrap"
android:background="#f6c0c0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="width=match height=match"
android:background="#c5e1b0"/>
</LinearLayout>
Horizontal LinearLayout
<?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">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="WrapWrap"
android:background="#c5e1b0"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="WrapMatch"
android:background="#f6c0c0"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="MatchMatch"
android:background="#c5e1b0"/>
</LinearLayout>
Note
The explanation in this answer assumes there is no margin or padding. But even if there is, the basic concept is still the same. The view border/spacing is just adjusted by the value of the margin or padding.
fill_parent will make the width or height of the element to be as
large as the parent element, in other words, the container.
wrap_content will make the width or height be as large as needed to
contain the elements within it.
Click here for ANDROID DOC Reference
fill_parent :
A component is arranged layout for the fill_parent will be mandatory to expand to fill the layout unit members, as much as possible in the space. This is consistent with the dockstyle property of the Windows control. A top set layout or control to fill_parent will force it to take up the entire screen.
wrap_content
Set up a view of the size of wrap_content will be forced to view is expanded to show all the content. The TextView and ImageView controls, for example, is set to wrap_content will display its entire internal text and image. Layout elements will change the size according to the content. Set up a view of the size of Autosize attribute wrap_content roughly equivalent to set a Windows control for True.
For details Please Check out this link : http://developer.android.com/reference/android/view/ViewGroup.LayoutParams.html

Categories

Resources