I have five buttons in a Relative layout, if I try to change their height dynamically, some buttons disappear.
How buttons are looking before clicking
Buttons after clicking
val w = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 45f, resources.displayMetrics)
btn_ran.setOnClickListener {
btn_1.layoutParams = RelativeLayout.LayoutParams(w.toInt(), 700)
btn_3.layoutParams = RelativeLayout.LayoutParams(w.toInt(), 700)
btn_4.layoutParams = RelativeLayout.LayoutParams(w.toInt(), 700)
btn_2.layoutParams = RelativeLayout.LayoutParams(w.toInt(), 700)
btn_5.layoutParams = RelativeLayout.LayoutParams(w.toInt(), 700)
}
All I want to do is to change all of the button's height randomly on the click of a button.
If You only want to change height to random value You can do it in this way:
button1.setOnClickListener {
val h = (100..500).random() //random integer between 100 and 500
button1.layoutParams.height = h
button2.layoutParams.height = h
button1.requestLayout() //refresh layout
}
I suspect that you are losing the relative positioning attributes when you create new LayoutParams objects. Remember that attributes like layout_toEndOf are part of the layout params.
Try this instead:
val w = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 45f, resources.displayMetrics)
btn_ran.setOnClickListener {
btn_1.updateLayoutParams { this.width = w }
btn_3.updateLayoutParams { this.width = w }
btn_4.updateLayoutParams { this.width = w }
btn_2.updateLayoutParams { this.width = w }
btn_5.updateLayoutParams { this.width = w }
}
This makes use of the updateLayoutParams extension function that is part of the Core KTX library. It will keep everything about the LayoutParams the same, but also allow you to modify the width.
If you can't use Core KTX, then you can be a little more verbose. Replace each of those calls with something like this:
val params1 = btn_1.layoutParams
params1.width = w
btn_1.layoutParams = params1
Related
I have a gridlayout with fixed height and weight paramaters. When screensize change automatically ıts getting bigger or smaller. Iv tried all methods but not succeed. How to fix?
My code ;
private fun loadBoard() {
for (i in boardCells.indices) {
for (j in boardCells.indices) {
boardCells[i][j] = ImageView(this)
boardCells[i][j]?.layoutParams = GridLayout.LayoutParams().apply {
rowSpec = GridLayout.spec(i)
columnSpec = GridLayout.spec(j)
width=340
height=400
bottomMargin = 5
topMargin = 5
leftMargin = 5
rightMargin = 5
}
boardCells[i][j]?.setBackgroundColor(
ContextCompat.getColor(
this,
R.color.white
)
)
boardCells[i][j]?.setOnClickListener(CellClickListener(i, j))
binding.layoutBoard.addView(boardCells[i][j])
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();
}
I am developing Android v2.2 app.
I have a Fragment. In the onCreateView(...) callback of my fragment class, I inflate an layout to the fragment like below:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.login, null);
return view;
}
The above inflated layout file is (login.xml):
<?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">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Username" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Username" />
</LinearLayout>
I would like to set a paddingTop to the above <LinearLayout> element , and I want to do it in the Java code instead of do it in xml.
How to set paddingTop to <LinearLayout> in my fragment Java class code ??
view.setPadding(0,padding,0,0);
This will set the top padding to padding-pixels.
If you want to set it in dp instead, you can do a conversion:
float scale = getResources().getDisplayMetrics().density;
int dpAsPixels = (int) (sizeInDp*scale + 0.5f);
To answer your second question:
view.setPadding(0,padding,0,0);
like SpK and Jave suggested, will set the padding in pixels. You can set it in dp by calculating the dp value as follows:
int paddingDp = 25;
float density = context.getResources().getDisplayMetrics().density
int paddingPixel = (int)(paddingDp * density);
view.setPadding(0,paddingPixel,0,0);
If you store the padding in resource files, you can simply call
int padding = getResources().getDimensionPixelOffset(R.dimen.padding);
It does the conversion for you.
Using Kotlin and the android-ktx library, you can simply do
view.updatePadding(top = 42)
See docs here
You can set padding to your view by pro grammatically throughout below code -
view.setPadding(0,1,20,3);
And, also there are different type of padding available -
Padding
PaddingBottom
PaddingLeft
PaddingRight
PaddingTop
These, links will refer Android Developers site. Hope this helps you lot.
Using TypedValue is a much cleaner way of converting to pixels compared to manually calculating:
float paddingDp = 10f;
// Convert to pixels
int paddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingDp, context.getResources().getDisplayMetrics());
view.setPadding(paddingPx, paddingPx, paddingPx, paddingPx);
Essentially, TypedValue.applyDimension converts the desired padding into pixels appropriately depending on the current device's display properties.
For more info see: TypedValue.applyDimension Docs.
Kotlin; extension function
fun Float.px(m: DisplayMetrics!): Int
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, m).toInt()
...
val pad = 10.0f.px
use below method for setting padding dynamically
setPadding(int left, int top, int right, int bottom)
Example :
view.setPadding(2,2,2,2);
Here you can see in which section the padding is applied
bidding.subHeader.tvSubHeader.setPadding(0, 5, 0, 0);
Someone edited this answer, but I added an image that had been removed before, here it is again
Step 1: First, take the padding value as an integer.
int padding = getResources().getDimensionPixelOffset(R.dimen.padding);
or int padding = 16; [Use any method]
Step 2: Then assign the padding value to the layout.
layout.setPadding(padding, padding, padding, padding);
layout.setPadding(padding_left, padding_top, padding_right, padding_bottom);
All side different padding can be assigned. layout.setPadding(16, 10, 8, 12);
For removing padding (No Padding) set padding values as 0,
layout.setPadding(0, 0, 0, 0);
Write Following Code to set padding, it may help you.
TextView ApplyPaddingTextView = (TextView)findViewById(R.id.textView1);
final LayoutParams layoutparams = (RelativeLayout.LayoutParams) ApplyPaddingTextView.getLayoutParams();
layoutparams.setPadding(50,50,50,50);
ApplyPaddingTextView.setLayoutParams(layoutparams);
Use LinearLayout.LayoutParams or RelativeLayout.LayoutParams according to parent layout of the child view
Context contect=MainActivity.this;
TextView tview=new TextView(context);
tview.setPaddingRelative(10,0,0,0);
The best way is not to write your own funcion.
Let me explain the motivaion - please lookup the official Android source code.
In TypedValue.java we have:
public static int complexToDimensionPixelSize(int data,
DisplayMetrics metrics)
{
final float value = complexToFloat(data);
final float f = applyDimension(
(data>>COMPLEX_UNIT_SHIFT)&COMPLEX_UNIT_MASK,
value,
metrics);
final int res = (int) ((f >= 0) ? (f + 0.5f) : (f - 0.5f));
if (res != 0) return res;
if (value == 0) return 0;
if (value > 0) return 1;
return -1;
}
and:
public static float applyDimension(int unit, float value,
DisplayMetrics metrics)
{
switch (unit) {
case COMPLEX_UNIT_PX:
return value;
case COMPLEX_UNIT_DIP:
return value * metrics.density;
case COMPLEX_UNIT_SP:
return value * metrics.scaledDensity;
case COMPLEX_UNIT_PT:
return value * metrics.xdpi * (1.0f/72);
case COMPLEX_UNIT_IN:
return value * metrics.xdpi;
case COMPLEX_UNIT_MM:
return value * metrics.xdpi * (1.0f/25.4f);
}
return 0;
}
As you can see, DisplayMetrics metrics can differ, which means it would yield different values across Android-OS powered devices.
I strongly recommend putting your dp padding in dimen xml file and use the official Android conversions to have consistent behaviour with regard to how Android framework works.
Using Jave's solution.
public static int getResourceDimension(Context context, String name, String defType, String defPackage) {
int sizeInDp = 0;
int resourceId = context.getResources().getIdentifier(name, defType, defPackage);
if (resourceId > 0) {
sizeInDp = context.getResources().getDimensionPixelSize(resourceId);
}
float scale = context.getResources().getDisplayMetrics().density;
int dpAsPixels = (int) (sizeInDp*scale + 0.5f);
return dpAsPixels;
}
then call when needed.
int statusBarHeight = getResourceDimension(getContext(), "status_bar_height",
"dimen", "android");
statusBarHeight = (int) (statusBarHeight + getResources().getDimension(R.dimen.fragment_vertical_padding));
view.setPadding(0, statusBarHeight, 0, 0);
While padding programmatically, convert to density related values by converting pixel to Dp.
binding.appBarMain.toolbar.setOnApplyWindowInsetsListener { _, insets ->
val statusBarSize: Int =
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).top
} else {
insets.systemWindowInsetTop
}
binding.appBarMain.appBarLayout.setPadding(0, statusBarSize, 0, 0)
return#setOnApplyWindowInsetsListener insets
}
All the layers of my game are scaled and positioned for a rootLayer with a ratio 2:1.
For example, under the java version I did that :
Config config = new Config();
config.width = 800;
config.height = 400;
JavaPlatform platform = JavaPlatform.register(config);
For Android I'd like to change the rootLayer to have the max width possible, and the height = width / 2.
For a resolution of 800x480 (like the Google Nexus S), the rootLayer would be in 800x400, and positioned at (0, 40).
Is it possible to do that ?
I finally found a way to do it. If playn developpers pass through here they may tell me if that's the best way to do it.
I override the setContentView method of the GameActivity. In the parent, the method append the GameViewGL to the main layout. So, I copied the code and modified it to add my size and position specifications :
#Override
protected void setContentView(GameViewGL view) {
BitmapDrawable bmp = new BitmapDrawable(getResources(), "");
getWindow().setBackgroundDrawable(bmp);
LinearLayout layout = new LinearLayout(this);
layout.setBackgroundColor(0xFFFF0000);
layout.setGravity(Gravity.CENTER);
layout.addView(view);
LayoutParams params = new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
);
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
if (size.y > size.x) {
params.width = size.y;
params.height = size.y / 2;
layout.setY((size.x - size.y / 2) / 2);
} else {
params.width = size.x;
params.height = size.x / 2;
layout.setY((size.y - size.x / 2) / 2);
}
getWindow().setContentView(layout, params);
}
I am coding a custom view, extended from RelativeLayout, and I want to resize it programmatically, How can I do?
the custom view Class is something like:
public ActiveSlideView(Context context, AttributeSet attr){
super(context, attr);
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(inflater != null){
inflater.inflate(R.layout.active_slide, this);
}
Android throws an exception if you fail to pass the height or width of a view.
Instead of creating a new LayoutParams object, use the original one, so that all other set parameters are kept. Note that the type of LayoutParams returned by getLayoutParams is that of the parent layout, not the view you are resizing.
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) someLayout.getLayoutParams();
params.height = 130;
someLayout.setLayoutParams(params);
this.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, theSizeIWant));
Problem solved!
NOTE: Be sure to use the parent Layout's LayoutParams. Mine is LinearLayout.LayoutParams!
This works for me:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();
In Kotlin, you can use the ktx extensions:
yourView.updateLayoutParams {
height = <YOUR_HEIGHT>
}
For what it's worth, let's say you wanted to resize the view in device independent pixels (dp): -
You need to use a method called applyDimension, that's a member of the class TypedValue to convert from dp to pixels. So if I want to set the height to 150dp (say) - then I could do this:
float pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150, getResources().getDisplayMetrics());
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) someLayout.getLayoutParams();
params.height = (int) pixels;
someLayout.setLayoutParams(params);
where the expression: getResources().getDisplayMetrics() gets the screen density/resolution
Here's a more generic version of the solution above from #herbertD :
private void resizeView(View view, int newWidth, int newHeight) {
try {
Constructor<? extends LayoutParams> ctor = view.getLayoutParams().getClass().getDeclaredConstructor(int.class, int.class);
view.setLayoutParams(ctor.newInstance(newWidth, newHeight));
} catch (Exception e) {
e.printStackTrace();
}
}
try a this one:
...
View view = inflater.inflate(R.layout.active_slide, this);
view.setMinimumWidth(200);
I used this way to increase width of custom view
customDrawingView.post(new Runnable() {
#Override
public void run() {
View view_instance = customDrawingView;
android.view.ViewGroup.LayoutParams params = view_instance
.getLayoutParams();
int newLayoutWidth = customDrawingView
.getWidth()
+ customDrawingView.getWidth();
params.width = newLayoutWidth;
view_instance.setLayoutParams(params);
screenWidthBackup = params.width;
}
});
With Kotlin and using dp unit:
myView.updateLayoutParams {
val pixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200f, context.resources.displayMetrics)
height = pixels.toInt()
}
I solved it this way.. I have basically a simple view inside xml file.
View viewname = findViewById(R.id.prod_extra);
prodExtra.getLayoutParams().height=64;
If you have only two or three condition(sizes) then you can use #Overide onMeasure like
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
And change your size for these conditions in CustomView class easily.
This is how it can be done in Kotlin:
updateLayoutParams:
val view = layoutInflater.inflate(R.layout.cell, binding.ssss, false).apply {
id = View.generateViewId()
updateLayoutParams {
height = 200
width = 400
}
}
binding.ssss.addView(view)
OR
layoutParams:
val view = layoutInflater.inflate(R.layout.cell, binding.ssss, false).apply {
id = View.generateViewId()
layoutParams.width = 200
layoutParams.height = 200
}
binding.ssss.addView(view)
if you are overriding onMeasure, don't forget to update the new sizes
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(newWidth, newHeight);
}
This is how I achieved this. In Sileria answer he/she did the following:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = customHeight;
layout.requestLayout();
This is correct, but it expects us to give the height in pixels, but I wanted to give the dp I want the height to be so I added:
public int convertDpToPixelInt(float dp, Context context) {
return (int) (dp * (((float) context.getResources().getDisplayMetrics().densityDpi) / 160.0f));
}
So it will look like this:
ViewGroup.LayoutParams params = layout.getLayoutParams();
params.height = convertDpToPixelInt(50, getContext());
layout.requestLayout();
This is what I did:
View myView;
myView.getLayoutParams().height = 32;
myView.getLayoutParams().width = 32;
If there is a view group that this view belongs to, you may also need to call yourViewGroup.requestLayout() for it to take effect.
fun View.setSize(width: Int, height: Int) {
updateLayoutParams {
this.width = width
this.height = height
}
}