Android - ConstraintLayout set Percent Height programmatically? - android

here is my layout :
...
<android.support.constraint.ConstraintLayout
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.6"
>
<android.support.constraint.ConstraintLayout
android:id="#+id/myclayout"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintHeight_percent="0.2"
app:layout_constraintTop_toTopOf="parent"
></android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
...
how to set constraintHeight_percent programmatically ?
I tried with ConstraintSet but did not work
ConstraintSet set = new ConstraintSet();
set.constrainPercentHeight(R.id.myclayout, (float) 0.4);
set.applyTo(((ConstraintLayout) vw.findViewById(R.id.myclayout)));

the right answer is :
ConstraintLayout mConstrainLayout = (ConstraintLayout) vw.findViewById(R.id.myclayout);
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) mConstrainLayout.getLayoutParams();
lp.matchConstraintPercentHeight = (float) 0.4;
mConstrainLayout.setLayoutParams(lp);

I went with using a ConstraintSet to update the width and height of a ConstraintLayout's child:
val set = ConstraintSet()
set.clone(parentLayout) // parentLayout is a ConstraintLayout
set.constrainPercentWidth(childElement.id, .5f)
set.constrainPercentHeight(childElement.id, .5f)
set.applyTo(parentLayout)
...the float values should be a percentage mapped to the unit interval.

I had the same question and thankfully found this post. I developed a virtual musical instrument app, a steel drum/pan app with eight different UIs having circular shaped main elements. I used one layout for all screen size for each of the eight UIs to reduce layout redundancy and wanted to keep the aspect ratio of the circular elements on most devices with different screen resolutions. So I had to use layout_constraintWidth_percent and layout_constraintHeight_percent to resize the parent layout according to device screen aspect ratio. I used #beginner's code above and combined with code for calculating screen aspect ratio and consequent implementation of the idea. Here is the code:
// instantiate constraint layout inside OnCreate
ConstraintLayout mcLayout =findViewById(R.id.layout_myConstraintLayout);
//determine display aspect ratio
WindowManager wm = (WindowManager)
this.getSystemService(Context.WINDOW_SERVICE);
assert wm != null;
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
assert display != null;
display.getMetrics(metrics);
float width = metrics.widthPixels;
float height = metrics.heightPixels;
float ratio = width/height;
float aspectRatio = round(ratio, 2);
Log.d("DISPLAYRATIO", "Display Ration is: " + displayRatio);
// create contraintlayout set for mConstraintLayout and params
ConstraintSet set = new ConstraintSet();
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams)
lowTenorBkg.getLayoutParams();
// set percent width and height acacording to screen display aspect ratio
if (aspectRatio > 1.30f && aspectRatio < 1.42f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.96f;
lp.matchConstraintPercentHeight = 0.78f;
} else if (aspectRatio > 1.40f && aspectRatio < 1.60f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.96f;
lp.matchConstraintPercentHeight = 0.83f;
} else if (aspectRatio > 1.58f && aspectRatio < 1.67f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.96f;
lp.matchConstraintPercentHeight = 0.93f;
} else if (aspectRatio > 1.65f && aspectRatio <= 1.71f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.92f;
lp.matchConstraintPercentHeight = 0.94f;
} else if (aspectRatio > 1.72f && aspectRatio <= 1.78f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.875f;
lp.matchConstraintPercentHeight = 0.94f;
} else if (aspectRatio > 1.78f && aspectRatio <= 2.05f) {
// Add constraints
lp.matchConstraintPercentWidth = 0.8f;
lp.matchConstraintPercentHeight = 0.93f;
}
lowTenorBkg.setLayoutParams(lp);
set.applyTo(mcLayout);
// put the round method inside the activity class
// method for rounding float number to decimal places
public static float round(float d, int decimalPlace) {
return BigDecimal.valueOf(d).setScale(decimalPlace,
BigDecimal.ROUND_HALF_UP).floatValue();
}

Related

ConstraintLayout: how to divide screen in two equal parts of screen height programmatically

How to divide the screen in two equal part wrt height with constraint layout programmatically?
For this, you need to set the height to zero then set the percent accordingly. For e.g.,
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) viewTop.getLayoutParams();
lp.height = 0;
lp.matchConstraintPercentHeight = (float) 0.5;
ConstraintLayout.LayoutParams lp2 = (ConstraintLayout.LayoutParams)viewBottom.getLayoutParams();
lp2.height = 0;
lp2.matchConstraintPercentHeight = (float) 0.5;
viewTop.setLayoutParams(lp);
viewBottom.setLayoutParams(lp2);

Changing text size according to the change in the button size

I have a toggle button that changes it's size as following :
protected int[] calculateCardWidth(int[] rowsCols) {
//Getting the screen size.
Display display = this.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
//cardWidHigh 0->width , 1 ->height.
cardWidHigh[0] = (int) (width / (rowsCols[1] + .25));
cardWidHigh[1] = (int) (height / (rowsCols[0] + 2));
return cardWidHigh;
}
I want to be able to change the text size according to the change in button size (it's width and height )dynamically, what is the best approach inorder to achieve this ?
You change the values of its LayoutParams, the parent will use the new values to rerender the screen at new positions:
LayoutParams p = cardView.getLayoutParams();
p.width = cardWidth[0];
p.height = cardWidth[1];
cardView.setLayoutParams(p);
cardView.getViewParent().invalidate();

ImageView from URL Not wrapping content with custom height

I have an image loading from a url using Glide, with the image I'm getting the image height. WHen I set the height, and width to match parent, the height is too high and there is empty space on bottom and top of image. The height is in pixels
This is how I'm setting height:
if (height != 0) {
height = convertPixelsToDp(height, mContext);
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
params.height = height;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);
}
XML:
<ImageView
android:id="#+id/listphoto"
android:adjustViewBounds="true"
android:layout_width="match_parent"
android:background="#dddddd"
android:layout_height="wrap_content"
android:scaleType="fitCenter"
/>
I tried experimenting with adjustViewBounds and scaleType but nothing is working. It's not wrapping the top and bottom. How can I make this work?
I've been working on this all night
UPDATE:
public static float convertPixelsToDp(float px, Context context){
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
float dp = px / ((float)metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
return dp;
}
Okay. So, the answer is very simple. We just need to change the height of the ImageView with respect to the width of the image and the width of the screen. Doing this will set the image properly in the ImageView:
private float getHeight(float height, float width) {
Display display = ((Activity) context).getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
return (height * size.x / width);
}
If your ImageView has some margin or padding set to it, use this instead:
private float getHeight(float height, float width, int containerHeight) {
return (height * containerHeight / width);
}
Then finally,
if (height != 0) {
height = (int) getHeight(height, width);
//or if has some margin or padding
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
params.height = height;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);
}
Or if has padding or margin:
if (height != 0) {
height = (int) getHeight(height, width, viewHolder.listphoto.getMeasuredWidth());
ViewGroup.LayoutParams params = viewHolder.listphoto.getLayoutParams();
params.height = height;
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
viewHolder.listphoto.setLayoutParams(params);
}
Note: It will be a better if you go with the second one. It will ensure that even when you apply some margin/padding to your ImageView, the image sets properly in the ImageView ignoring the padding/margin.
add these attributes
android:adjustViewBounds="true"
android:cropToPadding="false"
android:scaleType="fitXY"
android:scaleType="fitXY"
android:adjustViewBounds="true"
I think these two property will resolve the problem and please remove
android:scaleType="fitCenter"
Change width to
android:layout_width="wrap_content"
android:adjustViewBounds="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
This will work for you without giving scaleType.

How to fit an AlertDialog size to the image that contains

I'm trying to create a AlertDialog which will show an image in fullscreen. My problem is that the dialog does not fit the image.
I could scale the image to fit the horizontal or vertical limit (depending on the screen oreintation) with some code that I found. However , the dialog shows an empty space that I want eliminate.
My dialog shows this:
But I want that it fits the image without the left and right empty space, like this:
My code to create the alert dialog:
void showImage(String path, String name) {
// Get image from the aboslute path
BitmapDrawable bitmap = new BitmapDrawable(getActivity().getResources(), path);
// Construct the dialog
AlertDialog.Builder imageDialog = new AlertDialog.Builder(getActivity());
imageDialog.setTitle(name);
imageDialog.setCancelable(true);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.thumbnail, null);
ImageView image = (ImageView) layout.findViewById(R.id.imageView);
image.setImageDrawable(bitmap);
imageDialog.setView(layout);
imageAlert = imageDialog.create();
// Fullscreen
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
WindowManager manager = (WindowManager) getActivity().getSystemService(
Activity.WINDOW_SERVICE);
lp.copyFrom(imageAlert.getWindow().getAttributes());
lp.width = manager.getDefaultDisplay().getWidth();
lp.height = manager.getDefaultDisplay().getHeight();
imageAlert.getWindow().setAttributes(lp);
image.setMinimumWidth(lp.width);
image.setMinimumHeight(lp.height);
imageAlert.show();
}
My XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerHorizontal="true"
android:id="#+id/imageView"/>
</LinearLayout>
I have tried scaleType = fitXY, but it deforms the image.
How can I make the dialog fit the image keeping the same aspect ratio? Any help would be appreciate
I could find a way to solve my problem, but I dont know if its the best way to do it. I calculated the image size manually and set the image and dialog to this size.
First, I check which dimesion will limit the size of the image, and set the screen value to that dimesion. Then, I calculated the other dimesion in relation to the previous to keep the same ratio and the image is not deformed.
// Get screen size
WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
int screenHeight = size.y;
// Get image size
int imgHeight = bitmap.getBitmap().getHeight();
int imgWidth = bitmap.getBitmap().getWidth();
// Get dialog params
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.copyFrom(imageAlert.getWindow().getAttributes());
// Which dimension is bigger in relation to screen size
if (((float)imgHeight) / screenHeight > ((float)imgWidth) / screenWidth) {
// Height is bigger so width is calculated on relation to it to keep the same ratio
lp.height = screenHeight;
lp.width = (int) (imgWidth * ((float) screenHeight) / imgHeight);
}
else {
// Width is bigger so height is calculated on relation to it to keep the same ratio
lp.height =(int) (imgHeight * ((float) screenWidth) / imgWidth);
lp.width = screenWidth;
}
// Set the new size
image.getLayoutParams().width = lp.width;
image.getLayoutParams().height = lp.height;
image.requestFocus();
imageAlert.show();
imageAlert.getWindow().setAttributes(lp);
Use
imageDialog.getWindow().setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
Try doing this imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); and also make height and width match_parent as shown below:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_centerHorizontal="true"
android:id="#+id/imageView"/>
</LinearLayout>

Why does getWidth() is larger than getLayoutParams().width sometimes?

My code for fixing ImageView:
private void fixImageWidth() {
int parentHeight = getHeight();
if (parentHeight == 0 || getParent() == null)
return;
Drawable drawable = image.getDrawable();
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) image.getLayoutParams();
if (drawable != null) {
int height = drawable.getIntrinsicHeight();
int width = drawable.getIntrinsicWidth();
lp.width = (int) ((float)(parentHeight - lp.topMargin * 2) / height * width);
} else {
lp.width = LayoutParams.WRAP_CONTENT;
}
image.requestLayout();
}
But sometimes actually image bounds is not changed. Below you could see HierarchyViewer properties of that object:
EDIT:
After I lot for debugging I determined, sometimes requestLayout don't remeasure image view. How does this happens?
EDIT:
I found solution, but still don't know reason. Solution is below:
image.post(new Runnable() {
#Override
public void run() {
image.requestLayout();
}
});
Any ideas?
Because getWidth() and getLayoutParams().width are different things. 1st relates to the View, the second is a layout request to the parent. If the parent cannot match the request the View maybe laid out with a different width. In this case you have requested MATCH_PARENT in the layout height and since an ImageView has a default scaleType of FIT_CENTER therefore content aspect ratio is maintained so the width will change.

Categories

Resources