Get PopupWindow height which has been set to WRAP_CONTENT - android

Here's my code:
val inflater = LayoutInflater.from(this)
val popupView = inflater.inflate(R.layout.small_player, null)
val popupWindow = PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT/*, focusable*/)
popupWindow.elevation = 1.0f
popupWindow.showAtLocation(window.decorView, Gravity.CENTER, 0, window.decorView.height)
val height = popupWindow.contentView.height //returns 0
I also tried with popupView.height but it returns 0 and with popupWindow.contentView.layoutParams.height that returned -1
So how can I get this height?

This is a very common problem, your view isn't on the screen when you are trying to get its height
try this.
val inflater = LayoutInflater.from(this)
val popupView = inflater.inflate(R.layout.small_player, null)
val popupWindow = PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT/*, focusable*/)
popupWindow.elevation = 1.0f
popupWindow.showAtLocation(window.decorView, Gravity.CENTER, 0, window.decorView.height)
popupView.post{
val height = popupWindow.contentView.height
}
also check this for more View's getWidth() and getHeight() returns 0

You can use View.getMeasuredHeight() which gives you the actual height of the view.
The values you're getting now are the numerical representations used for MATCH_PARENT and WRAP_CONTENT

Related

Val cannot be reassigned while I try to create LinearLayout dynamically

I'm trying to create new LinearLayout with kotlin inside MainActivity.kt
for (i in 0 until tileArr.size){
var tileLayout: LinearLayout = LinearLayout(this)
tileLayout.marginBottom = 10
}
while it throws error Val cannot be reassigned on line: tileLayout.marginBottom = 10
You cannot modify those properties directly, you need to use LayoutParams.
for (i in 0 until tileArr.size){
var tileLayout: ViewGroup = LinearLayout(this)
val params = <Parent ViewGroup Type>.LayoutParams( // if the parent is FrameLayout, this should be FrameLayout.LayoutParams
LinearLayout.LayoutParams.WRAP_CONTENT, // modify this if its not wrap_content
LinearLayout.LayoutParams.WRAP_CONTENT // modify this if its not wrap_content
)
params.setMargins(0, 0, 0, 10) // last argument here is the bottom margin
tileLayout.layoutParams = params
}

Buttons in a RelativeLayout disappear after changing LayoutParams

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

How to set ImageView in CardView properly

So I'm making a gallery like app and it needs some ScrollView and CardView inside it.
This is the screenshot when I put some background in the ImageView
This is how it suppose to look, I have removed the background image here
I have tried to put an ImageView to inside the CardView with a Linear Layout but the Image filled the ScrollView Instead.
fun CreateCardView(ItemCount: Int){
for (i in 1 until ItemCount){
val card_view = CardView(this)
val param = GridLayout.LayoutParams()
param.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
param.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1f)
card_view.layoutParams = param
val param2 = card_view.layoutParams as GridLayout.LayoutParams
card_view.layoutParams = param2
subLayoutGrid?.addView(card_view)
val linearLayout = LinearLayout(this)
val layoutParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT, // CardView width
WindowManager.LayoutParams.WRAP_CONTENT // CardView height
)
linearLayout.layoutParams = layoutParams
linearLayout.setBackgroundColor(Color.parseColor("#135517"))
card_view.addView(linearLayout)
val imageView = ImageView(this)
val imageParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT
)
imageView.layoutParams = imageParams
imageView.setBackgroundResource(R.drawable.animaleight)
val layout = findViewById<LinearLayout>(finallinearId)
layout.addView(imageView)
}
}
How can i achieve something like on the image 2 using ImageView
I beleive it happens because u set width and height of your cardView as WRAP_CONTENT, and images that u put here is very big, so you should either change the size of images or use fixed size of cardView like 100dp height and 100dp-width, but that is not the best option or you can try to change your xml file, if you will put your xml file I will help you with that.
Also as long as it is LinearLayout try just put to every item "weight" parametr "1"

Open PopupWindow at top of the view

I want to have a show more button on click of which a popup should be opened with 3 options by default, but as per some logic then options would change ie. hide one of the options based on some condition.
I tried to add a popup menu:
popup = new PopupMenu(this, _showMore, GravityFlags.Top);
popup.MenuInflater.Inflate(Resource.Menu.showMoreMenu, popup.Menu);
if (!string.IsNullOrEmpty(someValue))
{
popup.Menu.FindItem(Resource.Id.ABC1).SetVisible(false);
}
popup.MenuItemClick += Popup_MenuItemClick;
popup.Show();
But in this case, initially, when I have all 3 options the popup is displayed above the button as there is less space below the show more button. But if I hide one of the options then my popup menu opens up at the bottom of the button. I want my popup menu to always be opened above the anchor button.
Then I also tried
PopupWindow popupWindow = new PopupWindow(this); // inflet your layout or diynamic add view
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.TestLayout, null, false);
TextView abc1 = (TextView)view.FindViewById(Resource.Id.abc1);
TextView abc2 = (TextView)view.FindViewById(Resource.Id.abc2);
TextView abc3 = (TextView)view.FindViewById(Resource.Id.abc3);
abc1.Click += abc1_Click;
abc2.Click += abc2_Click;
if (!string.IsNullOrEmpty(somecondition))
{
abc1.Visibility = ViewStates.Gone;
}
else
{
abc2.Visibility = ViewStates.Gone;
}
popupWindow.Focusable = (true);
popupWindow.Width = (WindowManagerLayoutParams.WrapContent);
popupWindow.Height = (WindowManagerLayoutParams.WrapContent);
popupWindow.ContentView = (view);
popupWindow.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
/*
//tried
var tttt= (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, Resource.Dimension._15sdp, Resources.DisplayMetrics);
//tried
int test=(int)(Resource.Dimension._15sdp * Resources.DisplayMetrics.Density);
//tried
float scale = Resources.DisplayMetrics.Density;
test= (int)(Resource.Dimension._15sdp * scale + 0.5f);
//tried
var dp = Resource.Dimension._15sdp;
int pixel = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, dp, Resources.DisplayMetrics);
*/
popupWindow.ShowAsDropDown(_showMore, -220, -570); <-- fixed offset which works for 3 options
The above code works but I have set fixed offset values which I assume will not render it correctly on different resolutions of the phone and also when I hide one of the options from the menu.
I also tried using ListPopupWindow but the same issue of setting the location. Can anybody please help me in setting offsets dynamically.
could it work like this :
int[] location = new int[2];
_showMore.getLocationOnScreen(location);
popupWindow.showAtLocation(_showMore,Gravity.NO_GRAVITY,location[0], location[1] - popupWindow.getHeight());
You can try below code:
fun showPopupAbove(anchor: View) {
viewAnchor = anchor
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {
popupWindow.showAsDropDown(anchor)
} else {
popupWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, 0, 0)
}
measureSizeThenUpdatePopupWindowPosition()
}
private fun measureSizeThenUpdatePopupWindowPosition() {
val viewTreeObserver = rootView.viewTreeObserver
if (!viewTreeObserver.isAlive) {
return
}
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
rootView.viewTreeObserver.removeOnGlobalLayoutListener(this)
val anchorRect = getRectFromView(viewAnchor)
// calculate x,y position for display popup window above/below..ect anchor view
var popupWinDownPositionX = (anchorRect.centerX() - rootView.width.toFloat() / 6).toInt()
var popupWinDownPositionY = anchorRect.top
// anchor view close to left
if (popupWinDownPositionX < 0) {
popupWinDownPositionX = 0
}
// anchor view close to top
if (popupWinDownPositionY < 0) {
popupWinDownPositionY = 0
}
// anchor view close to right
if (popupMayExceedsTheScreen(popupWinDownPositionX,
rootView.width)) {
popupWinDownPositionX = (Resources.getSystem().displayMetrics.widthPixels - rootView.width.toFloat()).toInt()
}
popupWindow.update(popupWinDownPositionX, popupWinDownPositionY,
rootView.width, rootView.height)
updateImageArrowMargin(popupWinDownPositionX)
}
})
}
You can modify the value of popupWinDownPositionX and popupWinDownPositionY to fit with your purpose
Thanks, #LeoZhu #LeoZhu's reply. I managed to get it working using the following code
PopupWindow popupWindow = new PopupWindow(this); // inflet your layout or diynamic add view
LayoutInflater inflater = (LayoutInflater)GetSystemService(Context.LayoutInflaterService);
View view = inflater.Inflate(Resource.Layout.TestLayout, null, false);
TextView abc1 = (TextView)view.FindViewById(Resource.Id.abc1);
TextView abc2 = (TextView)view.FindViewById(Resource.Id.abc2);
TextView abc3 = (TextView)view.FindViewById(Resource.Id.abc3);
abc1.Click += GenerateQR_Click;
abc2.Click += PrintQR_Click;
if (!string.IsNullOrEmpty(somecode))
{
abc1.Visibility = ViewStates.Gone;
}
else
{
abc2.Visibility = ViewStates.Gone;
}
int[] location = new int[2];
_showMore.GetLocationOnScreen(location);
popupWindow.Focusable = (true);
popupWindow.Width = (WindowManagerLayoutParams.WrapContent);
popupWindow.Height = (WindowManagerLayoutParams.WrapContent);
popupWindow.ContentView = (view);
popupWindow.SetBackgroundDrawable(new ColorDrawable(Color.Transparent));
view.Measure(View.MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified),
View.MeasureSpec.MakeMeasureSpec(0, MeasureSpecMode.Unspecified));
int yOffset = location[1] - (int)(view.MeasuredHeight );
popupWindow.ShowAtLocation(_showMore, GravityFlags.NoGravity, location[0], yOffset);

Set CardView height programmatically

I am new to Android dev and I'm having trouble trying to set the min height of a it.gmariotti.cardslib.library.view.CardView programmatically. I create a new instance of a CardView and set all the xml elements in code, but it does not affect the cardView. I do not inflate the cardview from xml.
CardView catCard = new CardView(getActivity());
catCard.setBackgroundColor(Color.green(0));
catCard.setMinimumHeight(10);
catCard.setBottom(0);
catCard.setExpanded(false);
CardView extends FrameLayout so you should be able to set LayoutParams. Try something like this :
CardView.LayoutParams layoutParams = (CardView.LayoutParams)
catCard.getLayoutParams();
layoutParams.height = 10;
, dont forget that setting Width is also required.
Or create new LayoutParams like this (not tested) :
CardView catCard = new CardView(getApplicationContext());
// sets width to wrap content and height to 10 dp ->
catCard.setLayoutParams(new CardView.LayoutParams(
CardView.LayoutParams.WRAP_CONTENT, 10));
catCard.setMinimumHeight(10);
myCardView.setLayoutParams(new RelativeLayout.LayoutParams(20, 20));
it depends that your cardview is a child of which layout, in this case it is under Relative Layout
My Solution with margin and it worked perfectly with me
val resources = context.resources // get resources from context
val width: Int = resources.displayMetrics.widthPixels / 3 //get width
val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, resources.displayMetrics).toInt() //set margin
val layoutParams = ViewGroup.MarginLayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT)
layoutParams.marginStart = px
layoutParams.marginEnd = px
cardView.layoutParams = layoutParams

Categories

Resources