Fill a GridLayout from Kotlin - android

I'm android studio noob. I'm trying to fill a grid layout from kotlin activity.
My code for the xml is this:
<androidx.gridlayout.widget.GridLayout
android:id="#+id/grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:rowCount="3"
app:columnCount="2">
</androidx.gridlayout.widget.GridLayout>
In the MainActivity there is a for to create every buttom like this:
val gridLayout: GridLayout = findViewById(R.id.grid)
for (i in 1..10){
val button = Button(this)
button.text = "Boton: " + i
// GridLayout.add(Buttom)
}
Who can I do it?
Thank you

Modify Your Function as Per the given Code.
for (i in 1..10){
val button = Button(this)
button.text = "Boton: " + i
val param = GridLayout.LayoutParams(
GridLayout.spec(
GridLayout.UNDEFINED, GridLayout.FILL, 1f
),
GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f)
)
button.layoutParams = param
gridLayout.addView(button)
}

I should change import android.widget.GridLayout to import androidx.gridlayout.widget.GridLayout;
And use gridLayout.addView(button) to add the button

Related

Having an imageview right aligned to a textview

Looking for a way to align an Imageview which would be in line with the textview and have it be able to adjust if the textview is too long and will extend to the next line. The reason it is an imageView, is I want it to be clickable
I haven't been successful, I have tried image and text spans and also constraintlayout but I can't seem to the get following result below:
Thanks
[1]: https://i.stack.imgur.com/onPT9.png
Here is a way to add an image to the end of the text in a TextView whether the text spans one or several lines. The approach is to add a space to the end of each text string and replace that space with an ImageSpan overlaid with a ClickableSpan.
Here is the layout used:
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#android:color/holo_blue_light"
android:padding="8dp"
android:text="#string/test_string_1"
android:textSize="28sp" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#android:color/holo_blue_light"
android:padding="8dp"
android:text="#string/test_string_2"
android:textSize="28sp" />
</androidx.appcompat.widget.LinearLayoutCompat>
And the string resources:
<string name="test_string_1"><b>This</b> is a short string.</string>
<string name="test_string_2"><b>This</b> is some text that spans several lines and is just used as an example.</string>
After waiting for the layout to complete, we can add the images to the end of the text for each TextView.
binding.root.doOnNextLayout {
// Make the drawables truly clickable.
binding.textView1.text = addEndImage(binding.textView1)
binding.textView1.movementMethod = LinkMovementMethod.getInstance()
binding.textView2.text = addEndImage(binding.textView2)
binding.textView2.movementMethod = LinkMovementMethod.getInstance()
}
private fun addEndImage(textView: TextView): Spannable {
// Get out (probable) StaticLayout from the TextView and some of its attributes.
val size = textView.layout.run {
val lastLine = lineCount - 1
-getLineAscent(lastLine) * 2 / 3
}
// Get the text and add a space for the spans at the end. If we are certain that the
// text can be accurately represented by an unspanned String, we could just use
// "${binding.textView.text} ".toSpannable()
val text = SpannableStringBuilder(textView.text).append(" ")
// Get the drawable and size it to fit on our last line.
val d = AppCompatResources.getDrawable(requireContext(), R.drawable.circle)!!
d.setBounds(0, 0, size, size)
// Set the ImageSpan to replace the space we added at the end. Vertical positioning
// and the size of the image may need to be tweaked.
val span = ImageSpan(d, ImageSpan.ALIGN_BASELINE)
text.setSpan(span, text.length - 1, text.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
// Set the ClickableSpan to overlay the ImageSpan we added at the end.
val clickableSpan = MyClickableSpan()
text.setSpan(
clickableSpan,
text.length - 1,
text.length,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
return text
}
class MyClickableSpan : ClickableSpan() {
override fun onClick(widget: View) {
Toast.makeText(widget.context, "Clicked", Toast.LENGTH_SHORT).show()
}
}
If you need to use an ImageView for accessibility or other reasons, you can do that as follows.
The layout:
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/holo_blue_light"
android:padding="8dp"
android:text="#string/test_string_2"
android:textSize="28sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="#+id/imageView"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="8dp"
android:src="#drawable/circle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Again, after layout is complete, we can do the following that will give the ImageView top and left margins that will place it at the end of the text.
binding.root.doOnNextLayout {
val imageView = binding.imageView
imageView.setOnClickListener() {
Toast.makeText(requireContext(), "Clicked", Toast.LENGTH_SHORT).show()
}
val textView = binding.textView2
val layout = textView.layout
val imageY = textView.bottom
val shiftX = layout.getLineRight(layout.lineCount - 1)
val shiftY =
-(imageView.y - imageY) - imageView.paddingTop - textView.height + layout.getLineBaseline(
layout.lineCount - 1
) - imageView.height / 2
val lp = (imageView.layoutParams as ViewGroup.MarginLayoutParams)
lp.marginStart = shiftX.toInt()
lp.topMargin = shiftY.toInt()
imageView.layoutParams = lp
}
You will have to work with the exact size and placement, but this is a technique that will work.

Putting labels on top of buttons in an Android app

I am trying to write a first Android app and I hit the following issue.
This is a loop handling some buttons:
for (i in 0..7) {
val btnID = resources.getIdentifier('N'.plus(i.toString()),"id",packageName)
val imageBtn = findViewById<ImageButton>(btnID)
imageBtn.setBackgroundColor(0x00)
imageBtn.setOnClickListener {
val result = Math.pow(2.toDouble(),i.toDouble()).toInt()
val textView = findViewById<TextView>(R.id.textView2).apply {//
text = result.toString()
}
}
// Here I want to put a sticker: "Hi" on top of the button (imageBtn).
.....
}
The code above works, and the buttons behave as I expect.
Now I would like to stick a label on top of each button.
How can I do that? I have already tried tens of ways, following sample code I found on the net, but nothing works.
Below is a graphic to illustrate what I mean more precisely.
Of course "Hi" cannot be part of the button image because I need to change it dynamically. It can later become "Ho", "He", "Pa", ... or whatever according to the state of the app.
Hope this might be work
for (i in 0..7) {
val btnID = resources.getIdentifier('N'.plus(i.toString()),"id",packageName)
val imageBtn = findViewById<ImageButton>(btnID)
imageBtn.setBackgroundColor(0x00)
val result = Math.pow(2.toDouble(),i.toDouble()).toInt()
imageBtn.setOnClickListener {
val textView = findViewById<TextView>(R.id.textView2).apply {//
text = result.toString()
}
}
// Here I want to put a sticker: "Hi" on top of the button (imageBtn).
imageBtn.text = result.toString()
}
Use this to your layout.
<RelativeLayout
android:id="#+id/layoutButton"
android:layout_width="60dp"
android:layout_height="60dp">
<ImageButton
android:id="#+id/imgBtn"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:layout_centerInParent="true"
android:textSize="20sp" />
</RelativeLayout>
And Give background as per you want to ImageButton.
For Constraintlayout Use this.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layoutButton"
android:layout_width="60dp"
android:layout_height="60dp">
<ImageButton
android:id="#+id/imgBtn"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hi"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="#+id/imgBtn"
app:layout_constraintEnd_toEndOf="#+id/imgBtn"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/imgBtn" />
</androidx.constraintlayout.widget.ConstraintLayout>
You can use simlpe Button widget instead of ImageButton, it has text propertie. To make the button round just set simple shape drawable to the background.
For example, create drawable circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#android:color/darker_gray"/>
</shape>
And use it in the Button widget:
<Button
...
android:background="#drawable/circle"
.... />
Since I had to spend some time and this may well be useful to someone else, I put here my solution. It now works exactly as I want.
Here it is:
for (i in 0..7) {
val btnID = resources.getIdentifier('N'.plus(i.toString()),"id",packageName)
val imageBtn = findViewById<ImageButton>(btnID)
imageBtn.setBackgroundColor(0x00)
imageBtn.setOnClickListener {
val result = Math.pow(2.toDouble(),i.toDouble()).toInt()
val textView = findViewById<TextView>(R.id.textView2).apply {//
text = result.toString()
}
}
setSticker(i,btnID)
}
fun setSticker(n:Int,btn:Int) {
val label = TextView(this)
label.id = View.generateViewId()
label.text = "Hi"
label.setTextColor(Color.rgb(0xFF,0xFF,0xFF))
label.setTypeface(null, Typeface.BOLD)
label.setTextSize(TypedValue.COMPLEX_UNIT_PX, 17.dpToPixels(this))
label.elevation = 0.dpToPixels(this) // To make the label visible (i.e. on top)
constraintLayout?.addView(label)
val constrSet = ConstraintSet()
constrSet.clone(constraintLayout)
constrSet.connect(label.id, ConstraintSet.LEFT, btn, ConstraintSet.LEFT)
constrSet.connect(label.id, ConstraintSet.RIGHT, btn, ConstraintSet.RIGHT)
constrSet.connect(label.id, ConstraintSet.TOP, btn, ConstraintSet.TOP)
constrSet.connect(label.id, ConstraintSet.BOTTOM, btn, ConstraintSet.BOTTOM)
constrSet.applyTo(constraintLayout)
}

ScrollView doesn't stretch enough

I have a LinearLayout(horizontal) inside a ScrollView. I'm trying to add TextView's and Button's inside LinearLayout with programmatically.
My code works without errors but with little glitch. My ScrollView only stretch for TextView not for Button's. Sorry for the inadequate explanation, maybe screenshot helps: Imgur.
❒ Eve gir. is a Button the rest is TextView.
How can I make ScrollView stretch and wrap my Button's too. i tried set the fillViewPort but it did not work.
TextView adding code:
private fun createText(prTx: String, color: String) {
val text = TextView(this)
text.text = prTx
text.gravity = Gravity.CENTER_HORIZONTAL
text.textSize = 18F
text.setShadowLayer(5F,3F,2F,Color.BLACK)
when (color) {
"n" -> text.setTextColor(Color.WHITE)
"p" -> text.setTextColor(Color.rgb(255,182,193))
"m" -> text.setTextColor(Color.rgb(182,207,255))
"cm" -> text.setTextColor(Color.rgb(182, 242, 227))
"olay" -> {
text.setShadowLayer(5F,3F,2F,Color.rgb(100,0,166))
text.setTextColor(Color.rgb(75,0,130))
}
}
text.textAlignment = TextView.TEXT_ALIGNMENT_CENTER
text.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
val layout = findViewById<LinearLayout>(R.id.llText)
layout.addView(text)
}
Button adding code
private fun createButton(prTx: String, clk: Int) {
val button = Button(this)
button.text = prTx
button.setBackgroundColor(Color.TRANSPARENT)
button.gravity = Gravity.CENTER_HORIZONTAL;
button.textSize = 18F
button.transformationMethod = null;
button.setTextColor(Color.WHITE)
button.setShadowLayer(10F,5F,5F, Color.BLACK)
button.textAlignment = TextView.TEXT_ALIGNMENT_CENTER
button.setOnClickListener {
when (clk) {
}
}
button.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT)
val layout = findViewById<LinearLayout>(R.id.llText)
layout.addView(button)
}
Layout's XML codes
<ScrollView
android:id="#+id/sv"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="#5B34515E"
android:fadeScrollbars="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="#+id/ivMutfak"
app:layout_constraintHeight_default="wrap"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/clMiddle"
app:layout_constraintTop_toBottomOf="#+id/clMiddle"
app:layout_constraintVertical_bias="0.0">
<LinearLayout
android:id="#+id/llText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
android:orientation="vertical" />
</ScrollView>
The problem was not ScrollView, it was LinearLayout. Problem solved when I deleted it android:layout_margin's of `LinearLayout. I still don't know why but this solution worked for me.
You should use LinearLayout.LayoutParams.WRAP_CONTENT instead of ViewGroup.LayoutParams.MATCH_PARENT. Try this code
LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT)

Update Image width and Margins programmatically

I have a drawable that's being displayed in a layout. The drawable has default properties such as color and width. I'm creating a data class to be able to update those when the recycler view is created. The part that fills in the color in the middle is working. But I'm stuck on how to actually update the drawable width and the ImageView margins from the viewHolder.
mydrawable.xml
The layout file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/rect_outline"
android:src="#drawable/mydrawable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</LinearLayout>
The data class
data class ImageData(
val c: String
val width: Int
val marginLeft : Int
)
MyViewHoler.kt
internal class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: ImageData) {
itemView.rect_outline.setColorFilter(Color.parseColor(item.c))
}
}
first put this into your xml image view component
android:scaleType="fitCenter"
my sugest is use scale with animation to get a good looking for the user
imageView.animate()
.scaleX(scaleValue)
.scaleY(scaleValue)
.setDuration(MOVING_ANIMATION_DURATION)
.start()
imageView.invalidate()
but you can set a new layout params like:
val l = imageView.layoutParams
l.height = value
l.width = value
imageView.layoutParams = l
you can do this way too
val params = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
params.setMargins(0, 20, 0, 40)
params.height = 1
params. width = 1
imageView.layoutParams = params

TextView not showing up when I add it to LinearLayout

I try to create a cardView that contains an image and beside that image I want to add two lines of text (vertically stacked on each other). Below is the code I have written to do this (the function returns a cardView). However, in my cardView nothing is appearing. If I remove the linearLayout and the textViews than I get a card which shows the imageView. So I assume I'm doing something wrong with the way I set the linearLayout on my textViews or the way I add my linearLayout to my tableRow.
private fun constructCardView(header: String, info: String) : CardView {
val cardView = CardView(this)
cardView.setPaddingRelative(5,0,0,0)
cardView.radius = 10F
val tableLayout = TableLayout(this)
val layoutParams = TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.MATCH_PARENT, 1.0f)
tableLayout.layoutParams = layoutParams
val tableRow = TableRow(this)
val tableRowParams = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1.0f)
tableRow.layoutParams = tableRowParams
val imageView = ImageView(this)
imageView.setImageResource(R.drawable.ic_restaurant_black_24dp)
imageView.minimumHeight = 10
imageView.minimumWidth = 10
val linearLayout = LinearLayout(this)
val linearLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
linearLayoutParams.setMargins(3,3,3,3)
linearLayout.layoutParams = linearLayoutParams
linearLayout.orientation = LinearLayout.VERTICAL
val textViewHeader = TextView(this)
val textViewHeaderLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
textViewHeaderLayoutParams.setMargins(0, 0, 5, 0)
textViewHeader.layoutParams = textViewHeaderLayoutParams
textViewHeader.text = header
textViewHeader.textSize = 20F
val textViewInfo = TextView(this)
val textViewInfoLayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
textViewInfoLayoutParams.setMargins(5, 0, 5, 0)
textViewInfo.text = info
textViewInfo.textSize = 12F
textViewInfo.layoutParams = textViewInfoLayoutParams
linearLayout.addView(textViewHeader)
linearLayout.addView(textViewInfo)
tableRow.addView(imageView)
tableRow.addView(linearLayout)
tableLayout.addView(tableRow)
cardView.addView(tableLayout)
cardView.requestLayout()
return cardView
}
Any help would be appreciated.
Just to offer an alternative if using xml is an option, as I think it saves up many many lines of code to get the same job done.
You probably want to use LinearLayout instead of the Tablelayout to stack things vertically or horizontally, as a more versatile approach. For example I used the layout_weight property to define how the rows are split in percentage.
Create an xml file in the layouts folder:
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/card_view"
android:layout_gravity="center"
android:layout_width="200dp"
android:layout_height="200dp"
card_view:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView android:layout_width="0dp"
android:layout_weight="0.4"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/header"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
Then in code:
private fun constructCardView(header: String, info: String) : CardView {
val cardView = LayoutInflater.from(this).inflate(R.layout.cardview, parent, false)
cardView.header.text = header
cardView.info.text = info
return cardView as CardView
}

Categories

Resources