Home > Back-end >  Playing (and having issues) with Layout on Android
Playing (and having issues) with Layout on Android

Time:09-02

I am having some problems getting the result I want using RelativeLayout, also wondering if I should also use LinearLayout at the same time. Here is my code:

package me.soft.myapp

import android.content.Context
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.TypedValue
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.ScrollView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout

class MainActivity : AppCompatActivity() {
    lateinit private var constraintLayout: ConstraintLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        constraintLayout = this.findViewById(R.id.activity_main)

        val relatLayOut = RelativeLayout(this)
        relatLayOut.id = View.generateViewId()
        val rllyLOP = RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT)
        relatLayOut.layoutParams = rllyLOP
        constraintLayout.addView(relatLayOut)

        // We define 2 colored stripes and one scroll view.
        val bannerOne = stripe("Hello wonderful world of yours ...",
            Color.rgb(0xEE,0xEE,0x22))
        val bannerTwo = stripe("The purpose of our lives is to be happy.",
            Color.rgb(0x22,0xEE,0xEE))
        val scrolZone = scrollBlock(longNumberString(1000))

        // We add them to the global layout.
        relatLayOut.addView(bannerOne)
        relatLayOut.addView(bannerTwo)
        relatLayOut.addView(scrolZone)

        // Set the layout and order of the components:
        val layoutOption = 2//1

        if (layoutOption == 1) {
            setViewBelow(bannerTwo,bannerOne)
            setViewBelow(scrolZone,bannerTwo)
        }

        if (layoutOption == 2) {
            setViewBelow(scrolZone, bannerOne)
            setViewBelow(bannerTwo, scrolZone)
        }
    }


    fun Int.dpToPixels(context: Context):Float = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,this.toFloat(),context.resources.displayMetrics
    )


    fun stripe(display:String, bgc: Int): RelativeLayout {
        val lnlyLOP = RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT)
        val lnlyOut = RelativeLayout(this)
        lnlyOut.id = View.generateViewId()
        lnlyOut.gravity = Gravity.CENTER
        lnlyOut.layoutParams = lnlyLOP
        lnlyOut.setBackgroundColor(bgc)

        val theLabel = TextView(this)
        theLabel.text = display
        theLabel.setTextSize(TypedValue.COMPLEX_UNIT_PX, 25.dpToPixels(this))
        theLabel.gravity = Gravity.CENTER
        lnlyOut.addView(theLabel)
        return lnlyOut
    } /* End of stripe */


    fun scrollBlock(display:String): ScrollView {
        val scrolViw = ScrollView(this)
        scrolViw.id = View.generateViewId()
        val rllyLOP = RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT
        )
        scrolViw.layoutParams = rllyLOP

        val theLabel = TextView(this)
        theLabel.text = display
        scrolViw.addView(theLabel)

        return scrolViw
    } /* End of scrollBlock */


    fun setViewBelow(theView: View, referView: View) { // To set theView below referView.
        val memoLOP = RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.WRAP_CONTENT)
        memoLOP.addRule(RelativeLayout.BELOW, referView.id)
        theView.layoutParams = memoLOP
    } /* End of setViewBelow */


    fun longNumberString(n:Int): String { // To make a long string of numbers.
        if (n<0) return ""
        var resultStr = "0"
        for (i in 1..n) {resultStr  = "-$i"}
        return resultStr
    } /* End of longNumberString */
}

This code is working as I expect when I use layoutOption = 1. But not when I use layoutOption = 2.

Here what I get on the device for layoutOption = 1 :

enter image description here

Here what I get on the device for layoutOption = 2 :

enter image description here

But here what I expect for layoutOption = 2 :

enter image description here

Obviously I am doing something wrong for the result I want with layoutOption = 2.

Can anyone see where the mistake is?

Here is the XML file, just in case:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/   res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@ id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" />

CodePudding user response:

Since you are using RelativeLayout, you could do something like this to achieve your desired results:

a. Make your bannerTwo bottom align to Parent bottom using LayoutParams#alignParentBottom

b. Make your ScrollView Bottom to be Top of bannerTwo using LayoutParams#layout_above

c. Similarly Make your ScrollView Top to be Bottom of bannerOne using LayoutParams#layout_below

This will lock in the size of the ScrollView between the two banners while making the bannerOne and bannerTwo visible on screen. Hope that helps.

CodePudding user response:

Thanks to the tips provided in Pratik K's answer; here is how I finally solved the problem from the code in the post. I replaced the following lines of code:

    if (layoutOption == 2) {
        setViewBelow(scrolZone, bannerOne)
        setViewBelow(bannerTwo, scrolZone)
    }

by the ones below:

    if (layoutOtion == 2) {
        stickViewAtBottom(bannerTwo)
        setViewBetween(scrolZone,bannerOne,bannerTwo)
     }

Where the two new functions stickViewAtBottom() and setViewBetween() are defined as:

fun stickViewAtBottom(theView: View) { // To set theView at the bottom of its parent.
    val memoLOP = RelativeLayout.LayoutParams(
        RelativeLayout.LayoutParams.MATCH_PARENT,
        RelativeLayout.LayoutParams.WRAP_CONTENT)
    val parentID = (theView.parent as View).id
    memoLOP.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, parentID)
    theView.layoutParams = memoLOP
} /* End of stickViewAtBottom */


fun setViewBetween(theView: View, aboveView: View, beneathView: View) {
    val memoLOP = RelativeLayout.LayoutParams(
        RelativeLayout.LayoutParams.MATCH_PARENT,
        RelativeLayout.LayoutParams.WRAP_CONTENT)
    memoLOP.addRule(RelativeLayout.BELOW, aboveView.id)
    memoLOP.addRule(RelativeLayout.ABOVE, beneathView.id)
    theView.layoutParams = memoLOP
} /* End of setViewBetween */
  • Related