Sunday 16 January 2022

Android FAB Action to appear across the Application

Recently we got a requirement to an existing product and which have some legacy implementation too. Here the requirement to have a FAB (Chat Bot) action to be available on all the application screens (Activity).

Discussion where went like below:

1. Adding FAB to all the activity is a very tedious process, even creating a common layout and add using <include> in all layout also not that simple task. 😟 (Bad Practice too)

2. Will create a simple FAB Action class and planned to initialize it in all the activity class, since it is also a required some more efforts to update the initialization code in all the activity classes. (This implementation will reduces the effort but not fully, It helps to update on our Common BaseActivity and few other independent Activities by doing the initialization)  😌   

3. Finally Achieved!..  Implemented through Application class and ActivityLifecycleCallbacks, which made the implementation easier to work seamlessly across the application. 😎

FabButton

object FabButton {
    fun init(activity: Activity, savedInstanceState: Bundle?=null) {
        val root: ViewGroup = activity.window.decorView as ViewGroup
        val fab = FloatingActionButton(activity).apply {
            id = View.generateViewId()
            setImageResource(android.R.drawable.sym_action_chat)
            elevation = 2f
            imageTintList = ColorStateList.valueOf(Color.WHITE)
            backgroundTintList = ColorStateList.valueOf(Color.RED)
            size = FloatingActionButton.SIZE_NORMAL
            isFocusable = true
            layoutParams = FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.WRAP_CONTENT,
                FrameLayout.LayoutParams.WRAP_CONTENT
            ).apply {
                gravity = Gravity.BOTTOM or Gravity.END
                setMargins(24, 24, 24, 24)
            }
        }
        fab.setOnClickListener {
            Toast.makeText(activity, "Yes, May I help you?", Toast.LENGTH_SHORT).show()
        }
        root.addView(fab)
    }
}

Activity

class FirstActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second2)
        FabButton.init(this)  // See here the fab initialization
    }
}

Later as per the #3, we found an other option instead of initializing the FabButton.init(this) to all the activities, implementing the below things resolved the issue without doing a larger code change.  

class TrailsApplication : Application(), Application.ActivityLifecycleCallbacks {
    override fun onCreate() {
        super.onCreate()
        registerActivityLifecycleCallbacks(this)
    }
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        FabButton.init(activity, savedInstanceState)
    }
// Override other class ... 
}

P.S:  The application class has to override all the interface method of the ActivityLifecycleCallbacks, so as per the standard it would be good to handle by creating a separate handler class and register the same on application class.   For the simple and understanding purpose, I have override all the methods of lifecycle callbacks in application class itself. 

Happy Coding :-) 

  

No comments: