You have the flexibility to add a new view to the existing chat UI. For example, a UI element like the FloatingActionButton is designed to overlay on top of other views. This means they are not constrained by the boundaries of existing components in the module. The following code shows how you can add such views to the module.
Define the new UI view in XML. The following demonstrates how to overlay a FloatingActionButton on the existing Channel screen.
First, define your new UI element in the XML layout. Below is an example showing how to overlay a FloatingActionButton on the existing Channel screen. In this XML layout, the channelViewFrameLayout serves as the placeholder for the Channel screen.
With the XML layout defined, the next step involves adjusting the view within onCreateView. First, inflate the UI constructed in view_channel_layout_sample.xml. Next, create the default Channel view using super.onCreateView(). Then, add it to the channelViewFrameLayout defined in the xml above. The implementation is shown in the code below.
class ChannelLayoutSampleModule(context: Context) : ChannelModule(context) {
override fun onCreateView(context: Context, inflater: LayoutInflater, args: Bundle?): View {
val binding = ViewChannelLayoutSampleBinding.inflate(inflater)
val channelView = super.onCreateView(context, inflater, args)
binding.channelView.addView(channelView)
binding.fab.setOnClickListener {
Toast.makeText(context, "Floating Button Clicked", Toast.LENGTH_SHORT).show()
}
return binding.root
}
}
You can rearrange the components of a module for a customized user experience. You retrieve the components from a module and call the component's onCreateView.
Note that for the default UI to operate correctly, you need to extract and apply the existing UIKit Theme when customizing.
override fun onCreateView(context: Context, inflater: LayoutInflater, args: Bundle?): View {
val moduleContext: Context = ContextThemeWrapper(context, params.theme)
val parent = LinearLayout(context)
parent.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
parent.orientation = LinearLayout.VERTICAL
val values = TypedValue()
if (params.shouldUseHeader()) {
moduleContext.theme.resolveAttribute(R.attr.sb_component_header, values, true)
val headerThemeContext: Context = ContextThemeWrapper(moduleContext, values.resourceId)
val headerInflater = inflater.cloneInContext(headerThemeContext)
val header = headerComponent.onCreateView(headerThemeContext, headerInflater, parent, args)
parent.addView(header)
}
val bodyContainer = FrameLayout(context)
bodyContainer.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 1.0f)
parent.addView(bodyContainer)
moduleContext.theme.resolveAttribute(R.attr.sb_component_list, values, true)
val listThemeContext: Context = ContextThemeWrapper(moduleContext, values.resourceId)
val listInflater = inflater.cloneInContext(listThemeContext)
val messageListLayout = messageListComponent.onCreateView(listThemeContext, listInflater, bodyContainer, args)
bodyContainer.addView(messageListLayout)
moduleContext.theme.resolveAttribute(R.attr.sb_component_status, values, true)
val statusThemeContext: Context = ContextThemeWrapper(moduleContext, values.resourceId)
val statusInflater = inflater.cloneInContext(statusThemeContext)
val statusLayout = statusComponent.onCreateView(statusThemeContext, statusInflater, bodyContainer, args)
bodyContainer.addView(statusLayout)
moduleContext.theme.resolveAttribute(R.attr.sb_component_channel_message_input, values, true)
val inputThemeContext: Context = ContextThemeWrapper(moduleContext, values.resourceId)
val inputInflater = inflater.cloneInContext(inputThemeContext)
val inputLayout = messageInputComponent.onCreateView(inputThemeContext, inputInflater, parent, args)
parent.addView(inputLayout)
}
For an in-depth practical demonstration, see our sample code.