Android PercentRelativeLayout width won't change with ratio when layout changed - android

I'm trying to make a textureview keep the 16:9 ratio when layout changes.
I use percentrelativelayout to implement it.
Also I need the textureview not exceed the screen size both on width/height. So I use 2 layers to make sure it won't exceed the screen.
It resize perfectly on layout preview in android studio. But the width isn't changing to keep the ratio in runtime on the device.
Here's the layout xml and the screenshot.
Have someone met the same question?
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center">
<android.support.percent.PercentRelativeLayout
android:id="#+id/percent"
app:layout_aspectRatio="178%"
app:layout_widthPercent="100%"
android:background="#android:color/darker_gray">
<TextureView
android:id="#+id/texture"
app:layout_aspectRatio="178%"
app:layout_heightPercent="100%"
android:layout_centerInParent="true">
</TextureView>
</android.support.percent.PercentRelativeLayout>
</android.support.percent.PercentRelativeLayout>
One layout in the bottom is set to VISIBLE
After bottom layout set to GONE

I had to play around with these PercentRelativeLayouts to get the result I was looking for too. Below is the code I used to get the same result you are looking for except I used a fragment. I've tested this on multiple devices and it worked on all of their different screen sizes. In your case, I would suggest replacing my "article_preview_frame" FrameLayout with your TextureView and see where that gets you. Make sure that you embed your PercentRelativeLayout inside a regular RelativeLayout.
<RelativeLayout
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:id="#+id/article_preview_relative_layout"
>
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/article_preview_container">
<FrameLayout
app:layout_widthPercent="100%"
app:layout_aspectRatio="178%"
android:layout_alignParentTop="true">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/article_preview_frame"
/>

Related

What does Android do when laying out components if there is not enough space?

Newbie question here, but I'm struggling to find the answer.
When laying out components, clearly if android can fit all the components on the screen while respecting all the requested attributes (height, margin etc), then it will do that.
But what if there is not enough room on the screen for everything? I had thought that it would simply put what it could on the screen starting at 0,0, and then have horizontal or vertical scrollbars for the rest.
However, that's not what I'm seeing, but I can't figure out what I am seeing. For example, when I try to view the following layout on my phone, the text has disappeared off the top of the screen (I can get this by turning the phone to landscape mode where there is obviously less available height).
What gives? How is android determining how to lay out these components and where to place the centre of the screen?
Many thanks!
EDIT: It looks like the problem has to do with me using so many dp values that mean that there's no way for everything to fit on the screen. I've fixed my immediate problem by using layout 'weight' to scale my components proportionally to the screen rather than trying to specify absolute sizes. I'm still curious why the layout code would choose to push my text off the top though - perhaps it priortises dp values?
The layout:
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context=".MainActivity">
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:text="#string/TextView1Text2" />
<Button
android:id="#+id/button"
android:layout_width="200dp"
android:layout_height="150dp"
android:onClick="#string/Button1OnClick"
android:text="#string/Button1Text" />
<ImageView
android:id="#+id/imageView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="#string/bla"
app:srcCompat="#drawable/blank_1024_200" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

ImageView vertically centred in MaterialCardView

Objective: I am trying to make a MaterialCard with an Image inside it, as well as some text below the Image. This current layout will serve as a "menu" for the application, where the user can select where to navigate to.
Problem: The ImageView is appearing vertically centred in the MaterialCardView. I would like the ImageView to "stick" to the top of the MaterialCardView. There are large sections of MaterialCardView above and below the ImageView.
My XML Code:
<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="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:liftOnScroll="true"
android:id="#+id/appBar">
<Toolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#color/design_default_color_primary_dark"
app:layout_scrollFlags="enterAlways">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/application_title"
android:textColor="#color/colorWhite"
android:textSize="24sp"/>
</Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:id="#+id/mealPlannerCardView"
android:contextClickable="true"
android:focusable="true"
app:cardBackgroundColor="#color/colorWhite">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:src="#drawable/wedding_dinner"
android:contentDescription="#string/wedding_background_cont_desc"/>
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:text="#string/mealPlannerTextView"
android:textColor="#color/design_default_color_primary_dark"/>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</ScrollView>
output
I tried to use layout_gravity="Top" but it made no difference.
EDIT
android:scaleType="fitStart" made the Image "stick" to the TOP of the MaterialCardView, but now very large space beneath the ImageView that requires scrolling to get to end.
Add the line below in your xml
android:layout_gravity="start|top"
See if this repositions the image for you. Worry about centring later if this works.
You might get the result you want by setting a scaleType for the image view.
Checkout this link: https://thoughtbot.com/blog/android-imageview-scaletype-a-visual-guide
It shows examples of each scaleType, it will help you to choose the right one to achieve the appearance you need.
This is happening because the Android framework is trying to maintain the aspect ratio in the face of your height and width constraints and default scale type.
There are more than one solutions to your problem and its for you to choose based on whose results are acceptable to you. All these solutions revolve around helping the framework with ImageView's aspect ratio. Let me try to put down the possible solutions that I can think of.
First solution can be as simple as changing the scale type on your ImageView as below:
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="#drawable/wedding_dinner"/>
That will take away the white spaces but crop your image.
A slight variation of the above, where you can define a fixed height of the image. This is a surprisingly widely used solution as it provides a certain
<ImageView
android:layout_width="match_parent"
android:layout_height="240dp"
android:scaleType="centerCrop"
android:src="#drawable/wedding_dinner"/>
Finally, a more elegant and better solution is to provide a fixed aspect ratio to your images using a ConstrainLayout.

How to resize an ImageView within a given Layout in Android?

I have a problem to make a proper layout for a special case. I experimented on that already for a while both in the designer and in code, but I couldn't find a solution, that's why I need your help.
I have to create a layout which should have a structure like pictured in the images below. It is mainly a combination of several linearLayouts. The problem I have is, that the picture can only be added within the code, because this layout is a detail view that displays information about items from a list.
On the top is the layout without an image place holder (no loaded picture - indicated in black), here the width of "linearLayout_BigLeft" is given by the width of the two buttons and the textView (which all have content) in the "linearLayout_BelowImage".
In the middle you see the layout after the picture has been loaded (image indictated in orange) in code. Depending on the aspect ratio of the android device the black colored gaps differ. I can't get the image to resize to the whole available height and adjusting its width accordingly. The "linearLayout_BelowImage" adjusts itself to the image size (the textView in it is getting wider).
On the bottom is the layout which shows the ideal state. The image always should use the whole available space in height and resize accordingly in width. The "linearLayout_BelowImage" adjusts itself to the image size (the textView in it is getting wider).
Question:
How can I get a layout (after the image is loaded in code) that looks like the bottom picture? The image, after loaded in code, has to resize itself, so it uses the whole available height and resizes its width accordingly. The "relativeLayout_Top" and the "linearLayout_BelowImage" have both fixed heights. The "scrollView_BigRight" adjusts itself based on the space that the "imageView_OrangeImage" doesn't need for itself.
I can deal with solutions that adjust the layout in code, after the image has been added, or solutions that makes the layout.xml itself flexilbe enough to deal with this situation.
Any help is highly appreciated. If you need any more information please let me know.
Below is the main content of my layout.xml, that is needed for this problem.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#color/white">
<RelativeLayout
android:id="#+id/relativeLayout_Top"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#color/blue" >
</RelativeLayout>
<LinearLayout
android:id="#+id/linearLayout_Big"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:background="#color/transparent" >
<LinearLayout
android:id="#+id/LinearLayout_BigLeft"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#color/transparent" >
<ImageView
android:id="#+id/imageView_OrangeImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#color/black" />
<LinearLayout
android:id="#+id/linearLayout_BelowImage"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="#color/blue_white_blue" >
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#color/blue" />
<TextView
android:id="#+id/textView_BelowImageMiddle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#color/white" />
<Button
android:id="#+id/btn2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#color/blue" />
</LinearLayout>
</LinearLayout>
<ScrollView
android:id="#+id/scrollView_BigRight"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#color/grey" >
</ScrollView>
</LinearLayout>
</LinearLayout>
android:adjustViewBounds="true"
This one’s a manual fix for “optimized” code in scaleType="fitCenter". Basically when Android adds an image resource to the ImageView it tends to get the width & height from the resource instead of the layout. This can cause layouts to reposition around the full size of the image instead of the actual viewable size.
AdjustViewBounds forces Android to resize the ImageView to match the resized image prior to laying everything else out. There are times where this calculation won’t work, such as when the ImageView is set to layout_width="0dip". If it’s not working, wrap the ImageView in a RelativeLayout or FrameLayout which handles the 0dip flexible size instead
get it from this site
OR
Mode android:scaleType="centerCrop" uniformly stretches the image to fill the entire container and trims unnecessary.
You can change the way it default scales images using the android:scaleType parameter. By the way, the easiest way to discover how this works would simply have been to experiment a bit yourself!
get it here

Resize ImageView to make entire layout fill screen

I have a screen that contains some TextViews and an ImageView inside a LinearLayout with vertical orientation. I would like the whole thing to fit exactly in the screen (no matter what its size is) where the ImageView is the one that adjusts itself to accommodate this.
I've seen here a few variations of this question (including this) but didn't find anything that really answers my requirement.
So far i've used a solution which is not very "pretty", which is putting the entire LinearLayout inside a ScrollView, and use a custom ImageView that on its onMeasure method calculates the delta between the height of the ScrollView to the height of the screen. If the former is larger than the latter then the delta is subtracted from the ImageView's measured height.
This solution is not perfect and i would really like to know if there is a better one. Im sure there is.
Appreciate your help.
EDIT: here is the layout xml
<com.xxx.widgets.LockableScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.venews"
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:scrollable="false"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="#dimen/login_horizontal_margin"
android:paddingRight="#dimen/login_horizontal_margin"
android:orientation="vertical">
<com.xxx.widgets.ResizableToFitScreenImageView android:id="#+id/login_logo_image"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="#dimen/login_logo_margin"
android:layout_marginBottom="#dimen/login_logo_margin"
android:src="#drawable/ic_logo_and_name"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/login_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"/>
<TextView android:id="#+id/login_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/login_username"/>
(...Other stuff...)
</RelativeLayout>
</LinearLayout>
</com.xxx.widgets.LockableScrollView>
EDIT2: and here's a sketch that i hope will make things clearer.
The sketch is showing 2 different screen sizes cause this solution would need to support also different devices with different screen sizes.
On the ImageView, set android:layout_height="0dp" and android:layout_weight="1". This will cause it to fill the remaining space (more about layout_weight here).
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>

Android: How to place a transparent image over another image with its exact width and height

I have 2 images main_bg and a transparent image ship. Ship is cropped from main_bg and I want to place cropped image ship on main_bg on the exact position where ship appears on main_bg. When I use
android:layout_width="match_parent"
android:layout_height="match_parent"
ship appear as an elongated one. When I use "wrap_content" instead of "match_parent",
it appear as a small image. How can I set ship on main_bg with its exact width and height.
This is my xml code.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/main_bg"
android:gravity="left"
android:orientation="horizontal">
<LinearLayout
android:id="#+id/ship"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ship"
android:orientation="vertical">
</LinearLayout>
How can I place it properly?
You should try using FrameLayouts to superimpose one image over the other. Like:
FrameLayout
Image
FrameLayout
Image
And set the dimensions of the FrameLayouts as you want to.
You can use two FrameLayout and do something like this :
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="#drawable/main_bg" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ship" >
</FrameLayout>
</FrameLayout>
use LayeredImageView from this post How to maintain multi layers of ImageViews and keep their aspect ratio based on the largest one?, see the example with a flag how to place layers

Categories

Resources