Home > Mobile >  How to write the same UI code from two activities in Kotlin?
How to write the same UI code from two activities in Kotlin?

Time:01-03

I have 2 activities with similar UI layouts, which contain some TextViews in the same place, that receive some text. I want to avoid writing this code twice, so I would like to create a class that will do the writing for both activities. The problem is that I need to pass the ViewBinding pointer to this class and then based on the type write either to Activity1 or Activity2. How can I do this?

Here is a solution that works but I am having to write the same code twice. Assume there are three TextViews.

// Activity1
class MainActivity : AppCompatActivity(), UiCommon {
    private lateinit var uib: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        uib = ActivityMainBinding.inflate(layoutInflater)
        setContentView(uib.root)
        
        // write common part
        val draw = DrawUiCommon(uib)
        draw.draw("a1_text1", "a1_text2", "a1_text3")
    }
}

// Activity2
class MainActivity2 : AppCompatActivity(), UiCommon {
    lateinit var uib: ActivityMain2Binding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        uib = ActivityMain2Binding.inflate(layoutInflater)
        setContentView(uib.root)
        
        // write common part
        val draw = DrawUiCommon(uib)
        draw.draw("a2_text1", "a2_text2","a3_text3")
    }
}

// Common part
class DrawUiCommon(val pt: androidx.viewbinding.ViewBinding){

    fun draw(t1: String, t2: String, t3: String){
        if (pt is ActivityMainBinding){
            pt.textView1.text = t1
            pt.textView2.text = t2
            pt.textView3.text = t3
        }
        else if (pt is ActivityMain2Binding){
            pt.textView1.text = t1
            pt.textView2.text = t2
            pt.textView3.text = t3
        }
    }
}

CodePudding user response:

As @sashabeliy said, if the ui is exactly the same and the only difference is the data to show, then you can receive the extra data in the intent. Is possible to create a method to do the navigation:

  companion object {
        private const val ARG_TEXT_LIST = "ARG_TEXT_LIST"

        fun navigate(context: Context, data: Array<String>) {
            val intent = Intent(context, MainActivity::class.java).apply {
                putExtra(ARG_TEXT_LIST, data)
            }
            context.startActivity(intent)
        }
    }

And then you can fetch the data in the onCreate lifecycle to populate the views:

 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(yourBinding.root)

        val textList = intent.getStringArrayExtra(ARG_TEXT_LIST)
        yourBinding.apply {
            textView1.text = textList[0]
            textView2.text = textList[1]
            textView3.text = textList[2]
        }
    }

CodePudding user response:

You didn't show your layout code, but based on your description, it sounds like you have some views in each activity layout that are the same.

Step 1 - extract those common views into it's own layout that you can resuse.

Step 2 - Reference the included layout:

// Activity2
class MainActivity2 : AppCompatActivity(), UiCommon {
    lateinit var uib: ActivityMain2Binding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        uib = ActivityMain2Binding.inflate(layoutInflater)
        setContentView(uib.root)
        
        // write common part
        val draw = DrawUiCommon(uib.includedLayout) // <-- Use included layout that has the comment views
        draw.draw("a2_text1", "a2_text2","a3_text3")
    }
}

// Common part
class DrawUiCommon(val pt: IncludedLayoutViewBinding ){ // <---Now we know the type

    fun draw(t1: String, t2: String, t3: String){
        //if (pt is ActivityMainBinding){ // <-- No if check needed
            pt.textView1.text = t1
            pt.textView2.text = t2
            pt.textView3.text = t3
        //}
        //else if (pt is ActivityMain2Binding){ // <-- No branch needed
        //    pt.textView1.text = t1
        //    pt.textView2.text = t2
        //    pt.textView3.text = t3
        //}
    }
}

OPTIONAL BONUS:

Create a Custom View that encapsulates this common layout and behavior.

Sample activity layout:

<LinearLayour>
    <MyCustomView>
    // OTHER THINGS
</LinearLayour>

Sample Activity:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    uib = ActivityMain2Binding.inflate(layoutInflater)
    setContentView(uib.root)
    
    // write common part
    uib.myCustomView.setValues("a2_text1", "a2_text2","a3_text3")
}

Sample Custom View:

class MyCustomView(...) {
    // Important init stuff up here ...


    fun draw(t1: String, t2: String, t3: String) {
        // Custom View creates and has its own binding
        binding.textView1.text = t1
        binding.textView2.text = t2
        binding.textView3.text = t3
    }
}
  • Related