I want to add a list of views to a layout. The views are added, but are not showing up.
val container:LinearLayout=findViewById(R.id.container)
val card:FrameLayout=findViewById(R.id.card)
card.setBackgroundColor(Color.parseColor("#E67E22"))
val cardlimiter=4
var cards= arrayOfNulls<FrameLayout>(10)
for(i in 0 until cardlimiter)
{
cards[i]= FrameLayout(card.context).apply{
setBackgroundColor(Color.parseColor("red"))
}
container.addView(cards[i])
}
In Android we already have a component for this approach for us, It's called Recyclerview, check this doc: https://developer.android.com/develop/ui/views/layout/recyclerview
Nothing showing up because of FrameLayout you are trying to add doest not have any width, height or padding. You must specify a valid LayoutParam or nothing will shown with empty width or height.
Try to take a look at how to programmaticly create a valid layoutParam with width and height.
val params : ViewGroup.LayoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
FrameLayout(card.context).apply {
setBackgroundColor(Color.parseColor("red"))
layoutParams = params
setPadding(10, 10, 10, 10)
}
Related
In my XML layout I define margins / padding as normal:
android:layout_marginBottom="54dp"
I then click a button, and I programatically override this by doing this:
param.setMargins(0, 0, 0, 0)
textInputLayout.layoutParams = param
Now, I need to click a button again, and it should go back to just reading the margin value that I defined in the XML layout. How can I clear / remove the custom margin?
I would expect there to be something like
param.clear()
Is there something like this? Or do I from this point forwards always need to override it programatically?
You have to set margins again after second time button click. Below code might help you.
// Instance variable
private var isSecondTime = false
// I have used FrameLayout as my parent, Replace with your parent layout. E.g LinearLayout
val params = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
And handle button click as per your requirement. Like:
button.setOnClickListener {
if (!isSecondTime) {
isSecondTime = true
params.setMargins(0, 0, 0, 0)
} else {
// setting margin again to 54 dp
//setMargins(left, top, right, bottom)
params.setMargins(0, 0, 0, convertDPToPx(54))
}
textView.layoutParams = params
}
Converting DP to Pixel:
private fun convertDPToPx(dip: Int): Int {
val r: Resources = resources
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dip.toFloat(),
r.displayMetrics
).toInt()
}
Each row in my RecyclerView is a single-row TextView with a certain size.
I'm looking for a general implementation such that the RecyclerView's height is set to correspond to the height of N such rows.
At the moment I'm using a magic value corresponding to 3 * rowHeight but it wouldn't be valid if I would change the text size of TextView.
Is this possible?
Edit: all rows have the same height
Make your itemView a LinearLayout which have vertical orientation. Then give it's width and height programmatically in your viewHolder like this.You have to calculate each rows width and height.
LayoutParams params = layout.getLayoutParams();
params.height = your_height;
params.width = your_width;
layout.setLayoutParams(params);
However if you have only 2,3 or 4 different heights, I mean these are specific for your recyclerView, you have to use getItemViewType() and make your different layouts and different ViewHolders for each type.
I ended up using the solution given in the comment.
Inflating the row view and then changing the layout params.
fun calculateRowHeight(layoutInflater : LayoutInflater, large: Boolean = true): Float {
val textView = layoutInflater
.inflate(R.layout.recycler_view_row, null) as TextView
val fm = textView.paint.fontMetrics
return fm.descent - fm.ascent
}
recyclerView.apply {
...
layoutParams.height = N * rowHeight.toInt()
}
I have studied many questions and answers in Stackoverflow, then I made a dummy function, that I run after a click in my app.
Here is the code:
fun openDialog(cx: Context) {
val alertDialog = Dialog(cx)
var linLayout = LinearLayout(cx)
linLayout.setOrientation(LinearLayout.VERTICAL);
// Set width, height and weight
linLayout.layoutParams = LinearLayout.LayoutParams(500,1000,1F)
// top and left position
linLayout.x = 0F
linLayout.y = 0F
val title = TextView(cx); // dummy view 1
title.setText("Custom Dialog 1")
title.setTextColor(Color.BLACK)
title.setTextSize(20F)
linLayout.addView(title) // add in layout
val msg = TextView(cx) // dummy view 2
msg.setText("Custom Dialog Box 2")
msg.setTextColor(Color.RED)
msg.setTextSize(10F)
linLayout.addView(msg) // add in layout
alertDialog.setContentView(linLayout) // Add the layout in Dialog
alertDialog.show(); // Show the dialog with layout
}
What I get? A proper dialog, but in the middle of the screen with width and height defined by the content. I also try to use the windows linked to the custom dialog without success.
val wlp = win.attributes
wlp.apply {
x = 0
y = 0
height = 1000
width = 500
}
win.attributes = wlp
No changes. However wlp.gravity = Gravity.BOTTOM works, but it's not enough for me. A also try to use win.setLayout(1000,500) without success
The Android documentation states:
Set the width and height layout parameters of the window. The default
for both of these is MATCH_PARENT; you can change them to WRAP_CONTENT
or an absolute value to make a window that is not full-screen.
Why can’t I resize and position the layout that I assign to my dialog?
Has somebody a hint?
The cell phone screen:
Update
I've got to change the position of dialog using
wlp.gravity = Gravity.TOP or Gravity.LEFT
wlp.x = 100 // Relative to left
wlp.y = 200 // relative to top
I keep trying to figure out how to change the width and height.
Set the layout params for the view you're inflating when you set the content :
this line :
alertDialog.setContentView(linLayout)
should be :
alertDialog.setContentView(linLayout, LinearLayout.LayoutParams(500,1000,1F))
You can also remove the explicit setting of the params for the LinearLayout
I'm currently working on animation that will grow up the view if the user clicks it. Basically, its a card that, when clicked, it will reveal the bottom content. For that, I'm extending Animation like this:
Val collapseAnimation = object : Animation() {
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
val interpolatedInverted = 1 - interpolatedTime
val headerLp = headerImage.layoutParams
headerLp.width = ...
headerImage.layoutParams = headerLp
}
}
The problem is that i need to get the height of a view (wrap_content) that is defined in XML as 0dp. Basically, I want to grow up a view from 0dp to wrap_content and for that i need to know what is the wrap_content size.
How can I accomplish that in the most efficient way, without hard coding the view size?
In order to measure a view with different layout params and get its height, we can do the following:
contentContainer.measure(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
val contentContainerFinalHeight = contentContainer.measuredHeight
I have a relative layout which I am creating programmatically:
RelativeLayout layout = new RelativeLayout( this );
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT);
Now I have two buttons which I want to add in this relative layout. But the problem is both buttons are being shown on the left of the RelatiiveLayout overlapping on each other.
buttonContainer.addView(btn1);
buttonContainer.addView(btn2);
Now I want to know how can I programmatically set the the android:layout_alignParentRight="true"
or android:layout_toLeftOf="#id/btn" attribute of buttons as we do in the xml?
You can access any LayoutParams from code using View.getLayoutParams. You just have to be very aware of what LayoutParams your accessing. This is normally achieved by checking the containing ViewGroup if it has a LayoutParams inner child then that's the one you should use. In your case it's RelativeLayout.LayoutParams. You'll be using RelativeLayout.LayoutParams#addRule(int verb) and RelativeLayout.LayoutParams#addRule(int verb, int anchor)
You can get to it via code:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)button.getLayoutParams();
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
params.addRule(RelativeLayout.LEFT_OF, R.id.id_to_be_left_of);
button.setLayoutParams(params); //causes layout update
For adding a RelativeLayout attribute whose value is true or false use 0 for false and RelativeLayout.TRUE for true:
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) button.getLayoutParams()
params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE)
It doesn't matter whether or not the attribute was already added, you still use addRule(verb, subject) to enable/disable it. However, post-API 17 you can use removeRule(verb) which is just a shortcut for addRule(verb, 0).
you need to create and id for the
buttons you need to refference:
btn1.setId(1);
you can use the params variable to
add parameters to your layout, i
think the method is addRule(), check
out the android java docs for this
LayoutParams object.
Kotlin version:
Use these extensions with infix functions that simplify later calls
infix fun View.below(view: View) {
(this.layoutParams as? RelativeLayout.LayoutParams)?.addRule(RelativeLayout.BELOW, view.id)
}
infix fun View.leftOf(view: View) {
(this.layoutParams as? RelativeLayout.LayoutParams)?.addRule(RelativeLayout.LEFT_OF, view.id)
}
infix fun View.alightParentRightIs(aligned: Boolean) {
val layoutParams = this.layoutParams as? RelativeLayout.LayoutParams
if (aligned) {
(this.layoutParams as? RelativeLayout.LayoutParams)?.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
} else {
(this.layoutParams as? RelativeLayout.LayoutParams)?.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0)
}
this.layoutParams = layoutParams
}
Then use them as infix functions calls:
view1 below view2
view1 leftOf view2
view1 alightParentRightIs true
Or you can use them as normal functions:
view1.below(view2)
view1.leftOf(view2)
view1.alightParentRightIs(true)
In Kotlin:
val params = mBinding.tvTotalAmount.layoutParams as RelativeLayout.LayoutParams
params.addRule(RelativeLayout.ALIGN_PARENT_END)
mBinding.tvTotalAmount.layoutParams = params