Display another composable layout if one is two wide for screen - android

Context:
In the app, there are dynamic questions from the backend asking users to select an option, usually two or three options.
The first choice design is to display the options as buttons in a row. But sometimes, the button texts could be very long that the buttons or the texts are not displayed properly on a mobile phone. In this case, the options should be displayed as a dropdown.
What tried:
To get the width of the button row, I tried to create a mutableState isBtnStyle var, pass a callback lambda to the button layout composable, get and pass back the row width, compare the row width with the screen width, and if the row width is bigger, display the dropdown layout.
val screenWidth = Resources.getSystem().displayMetrics.widthPixels
var isBtnStyle by remember {mutableStateOf(true)}
val rowWidth = { width: Int ->
if ( width > screenWidth ) isBtnStyle = false
}
if(isBtnStyle){
btnStyleComposable(rowWidth)
} else {
dropdownStyleComposable()
}
The problem:
The button layout composable is always displayed first for measuring the width, then the dropdown composable is displayed if the button layout is too wide for the screen.
Question:
How could I get the width of the row of buttons before the row is visually displayed, so the decision can be made on which composable layout to be displayed?
Thank you

Here is your answer.
For sake of minimum message length, I will add that I prefer to use Modifier.onPlaced.

Related

android, how to set a same height for my cards without hardcode in lazy row

I have a lazy row with items that have wrap content height.
my problem is that some texts of these items is visible or invisible base of that item. so the height of that cart is not fix and it will change.
how can I find the max height of that item (with all texts) and set that height to all items.
I do not want to set a hard code height to my items (like 300.dp)
as you can see in this image: the below button change its position based on the card's height.
I want that button fix in its place and not move up and down.
https://i.stack.imgur.com/R0Tc6.png
how can I fix that problem?
Have you tried experimenting around onGloballyPositioned{..} modifier property?
val localDensity = LocalDensity.current
Text(modifier = Modifier
.onGloballyPositioned { thisText ->
with (localDensity) {
thisText.size.height.toDp()
}
},
text = "Text"
)
Edit: Intrinsic Measurement is not allowed in LazyList components, have a look at this post, looks like similar to yours.
Jetpack Compose: Row with all items same height
Also, Constraintlayout maybe a good thing to experiment on.
One of the rules of Compose is that you should only measure your children once; measuring children twice throws a runtime exception. However, there are times when you need some information about your children before measuring them.
If you have a look at the Android documentation for Intrinsic Measurements, you will have a clear idea of what to do. In your scenario, you need to force Compose to measure the size of your children to adjust the parent composable's dimensions accordingly.
This medium article gives an easier example on how to use IntrinsicSize in Compose.

RecyclerView height of item

I have problem with measuring height of box.
I got two boxes (overlayed) :
One is displaying text etc and second box is when settings buttons will be clicked.
I got problem like a photo below
holder.local_normal_box.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
var height: Int = holder.local_normal_box.getMeasuredHeight()
holder.local_settings_box.maxHeight = height
holder.local_settings_box.minHeight=height
Blue overlay is settings box.
Use ConstraintLayout instead of LinearLayout. It is the layout recently recommended by Google

Calculate Button dimensions by its caption (text) without creating it

If I know the text for a Button, is there any way to calculate the button dimensions (width and height) before creating the button?
Buttons have the same chrome, paddings, margins, and font. They just vary system by system. So, in theory, button dimensions can be determined by its text.
In case you wonder why I would want to do that, I want to create a dynamic array of horizontal buttons, and if there is not enough space I would to create a menu instead of the excess buttons.
You can try something like this:
Button button = new Button(context);
button.setText("Testing");
button.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
int width = button.getMeasuredWidth();
int height = button.getMeasuredHeight();
As far as I know, if you are creating it from java, it'll give you proper values always.

ListView in page without messing up scrolling

What I'm trying to achieve:
--- Stack Layout / Relative Layout---
- some widget (e.g. Label) -
- some widget (e.g. Label) -
- ListView -
-------------------------------------
However, I also want the following scroll behaviour:
Top widgets disappear first then ListView starts scrolling. Basically, I want a "natural" scrolling behaviour.
One way I can achieve this is by making the whole page a ListView and putting the widgets as a Header for the ListView
But that has one problem... which I think is a bug in Xamarin.Forms:
If you have a long Label (what else to hold text?), it will not display all of it. It will actually make it scrollable and display only part of it at a time. What makes this even worse is that you cannot scroll the Label "easily", you have to try multiple times to make it scroll the label instead of the page, it's obviously bugged. That happens even if the page itself has hit the end (i.e. can't scroll any more), the Label still can't be scrolled easily.
Is there another way or a workaround to achieve what I want?
As one of the comments suggests, the best is to set the HeightRequest of the Label to the needed value.
Here is how I measure the height of the text on Android (you'll need DependencyService, if you want to call this function from Xamarin.Forms):
double measureString(string text, string font, double fontSize, double width)
{
var textView = new TextView(global::Android.App.Application.Context);
textView.Typeface = Android.Graphics.Typeface.Create(font, Android.Graphics.TypefaceStyle.Normal);
textView.SetText(text, TextView.BufferType.Normal);
textView.SetTextSize(Android.Util.ComplexUnitType.Px, (float)(fontSize * Xamarin.Forms.Forms.Context.Resources.DisplayMetrics.ScaledDensity));
int widthMeasureSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec((int)(width * Xamarin.Forms.Forms.Context.Resources.DisplayMetrics.Density), width == 0 ? Android.Views.MeasureSpecMode.Unspecified : Android.Views.MeasureSpecMode.Exactly);
int heightMeasureSpec = Android.Views.View.MeasureSpec.MakeMeasureSpec(0, Android.Views.MeasureSpecMode.Unspecified);
textView.Measure(widthMeasureSpec, heightMeasureSpec);
textView.SetIncludeFontPadding(false);
return (width == 0 ? textView.MeasuredWidth : textView.MeasuredHeight) / Xamarin.Forms.Forms.Context.Resources.DisplayMetrics.Density;
}

How to make my android component as size dependent for various display screen sizes?

I am making an android component which allows user to pick date from it. It can be helpful for developer who wants user to select date in his app. In my basic view, I have TextView where date from pop up will be populated into it and I have a button beside TextView. When a User clicks on the button, my component gets popped out and displays Dates. The component gets pops out in a Popup window and shows dates as month view and user also can switch from next-previous months, next-previous years just like we do in Calendar. Check the Image.
http://s15.postimage.org/ujw8py60b/stackoverflow.jpg (Sorry, I couldn't upload an image here because I am not allowed as I am new User here)
Each date is a TextView with the width of 35 and height as 30 set by me. DaysDisplayBar is also of some size set by me. So this component's whole width is 245 and height is around 200. Which is for mobile screen size.
I want to make this component as size dependent for various screen display sizes. For e.g. If it is being viewed on Tablet or Pad, it should be bigger in size than what its size on mobile phone screen. That is, For various displays its size should be changed to some value like max 1/3 of display size or like that something.
What can be the solution for this? According to me, some mathematics is needed here, some formula, equations etc. how about Parabola? Please help, I am dumb in maths totally. Thanks! :D
"Each date is a TextView with the width of 35 and height as 30 set by me. DaysDisplayBar is also of some size set by me. So this component's whole width is 245 and height is around 200. Which is for mobile screen size."
^^ is the problem. Sizes should be defined relative to the layout, not absolute. For example, the calendar has 7 columns (one for each day). Instead of making each one 35px, make each 1/7th of the screen.
SO:
I am assuming a DaysDisplayBar is a row containing 7 TextViews (one for each day). If that is true, why not call it a Week? Either way, The trick is in layout_wieght. Make all elements fill_parent, and all with the same weight of 1. This will evenly distrubate all elements in the parent. In your case, the parent is a DaysDisplayBar.
SO:
set DaysDisplayBar attribute `layout_width="fill_parent"
For each TextViewset attribute layout_width="fill_parent" ANDlayout_weight="1"`
hope that helps!
First of all, make sure you use density pixels (dip) instead of pixels.
Second, you can get the screen width and height, and from there, calculate your component size.
You can get the screen dimensions using the Display class getSize() method:
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
int screenWith = screenSize.x;
Or you can get the parent view dimensions:
MarginLayoutParams params = (MarginLayoutParams)parentView.getLayoutParams();
int padding = parentView.getPaddingLeft() + parentView.getPaddingRight();
int margin = params.leftMargin + params.rightMargin;
int measuredWidth = parentView.getMeasuredWidth() - padding - margin;
That way you know how much space you have inside the parent view element for your component.
Remember to convert any hard coded value to dip, you can do it this way:
public static int getDensitySize(float size) {
float density = getResources().getDisplayMetrics().density;
return (int)(density * size);
}
You do all of this from your onMeasure method to set your view size, and later on the onDraw you'll use this measure to draw your component.

Categories

Resources