Last active
August 5, 2021 01:32
-
-
Save darylsze/5b08888207176374d10c33d93ca1a233 to your computer and use it in GitHub Desktop.
Converted legacy pain old Java code to Kotlin with builder pattern for rich functional Toolbar setup. Just demo some basic usage, removed a lots of legacy functions internally.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
val config = ToolbarConfig( | |
lefts = listOf( | |
ToolbarButton( | |
action = ToolbarAction.ARROW_BACK, | |
clickHandler = { finish() } | |
) | |
), | |
middle = ToolbarSearchConfig( | |
hint = System.getLocalString("chat_common_search_message_bar_placeholder"), | |
onTextChange = { keyword -> | |
viewModel.keywordChangingObs.postValue(keyword) | |
if (keyword.isEmpty()) { | |
navController.navigateUp() | |
} else if(navController.currentDestination?.id != R.id.chatGroupSearchMainFragment) { | |
gotoMainPage() | |
} | |
}, | |
onFocus = { | |
if (viewModel.keywordChangingObs.value?.isNotEmpty() == true | |
&& navController.currentDestination?.id != R.id.chatGroupSearchMainFragment | |
) { | |
gotoMainPage() | |
} | |
}, | |
onClose = { | |
navController.navigateUp() | |
}, | |
onSearch = { keyword -> | |
onSearchKeyword(keyword) | |
} | |
) | |
) | |
fun usage() { | |
val toolbar = MyToolbar(context) | |
toolbar.setup(toolbarConfig); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context | |
import android.util.AttributeSet | |
import android.view.Gravity | |
import android.view.LayoutInflater | |
import android.view.View | |
import android.view.ViewGroup | |
import android.view.inputmethod.EditorInfo | |
import android.widget.EditText | |
import android.widget.ImageView | |
import android.widget.TextView | |
import androidx.annotation.ColorInt | |
import androidx.annotation.DrawableRes | |
import androidx.appcompat.widget.Toolbar | |
import androidx.constraintlayout.widget.ConstraintLayout | |
import androidx.core.view.isVisible | |
import androidx.fragment.app.FragmentActivity | |
import com.jakewharton.rxbinding3.view.clicks | |
import kotlinx.android.synthetic.main.toolbar.view.* | |
import java.util.concurrent.TimeUnit | |
enum class ToolbarAction(@DrawableRes val drawableRes: Int) { | |
ARROW_BACK(R.drawable.button_native_back_android), | |
HAMBURGER(R.drawable.ic_hamburger_menu), | |
SETTING(R.drawable.button_setting), | |
NOTIFICATION(R.drawable.button_notification_nonews), | |
NOTIFICATION_DOT(R.drawable.button_notification_news), | |
DELETE(R.drawable.button_delete), | |
CROSS(R.drawable.button_cross_white) | |
} | |
data class TextStyle @JvmOverloads constructor( | |
val color: Int? = null | |
) | |
data class ToolbarButton @JvmOverloads constructor( | |
val action: ToolbarAction? = null, | |
val text: String? = null, | |
val textStyle: TextStyle? = null, | |
val showRadiusBorder: Boolean = false, | |
val clickHandler: (View) -> Unit | |
) | |
interface IToolbarMiddleConfig | |
enum class ToolbarStyle { | |
TRANSPARENT, MAIN, BLACK, MAIN_DAYNIGHT, PURPLE | |
} | |
data class ToolbarTitleConfig @JvmOverloads constructor( | |
val title: String = "" | |
) : IToolbarMiddleConfig | |
data class ToolbarSearchConfig @JvmOverloads constructor( | |
val hint: String = "", | |
val onSearch: ((String) -> Unit)? = null, | |
val onFocus: (() -> Unit)? = null, | |
val onClick: (() -> Unit)? = null, | |
val onClose: (() -> Unit)? = null, | |
val onTextChange: ((String) -> Unit)? = null | |
): IToolbarMiddleConfig | |
data class ToolbarImageConfig @JvmOverloads constructor( | |
val imageResId: Int, | |
) : IToolbarMiddleConfig | |
data class ToolbarConfig @JvmOverloads constructor( | |
val style: ToolbarStyle = ToolbarStyle.MAIN, | |
val lefts: List<ToolbarButton>? = null, | |
val middle: IToolbarMiddleConfig?, | |
val rights: List<ToolbarButton>? = null | |
) { | |
fun changeStyle(style: ToolbarStyle): ToolbarConfig { | |
return copy(style = style) | |
} | |
} | |
private enum class Orientation { | |
LEFT, RIGHT | |
} | |
class MyToolbar @JvmOverloads constructor( | |
context: Context, | |
attrs: AttributeSet? = null, | |
defStyle: Int = 0 | |
) : ConstraintLayout(context, attrs, defStyle) { | |
private val iconSize: Int | |
private val borderButtonPadding: Int | |
init { | |
LayoutInflater.from(context).inflate(R.layout.toolbar, this, true) | |
iconSize = context.resources.getDimensionPixelSize(R.dimen._18sdp) | |
borderButtonPadding = context.resources.getDimensionPixelSize(R.dimen._8sdp) | |
} | |
lateinit var config: ToolbarConfig | |
fun setup(_config: ToolbarConfig) { | |
// clean up cached config | |
reset() | |
if (context is FragmentActivity) { | |
pushToTop(context as FragmentActivity) | |
} | |
config = _config | |
setupInternal() | |
} | |
fun getToolbar(): Toolbar { | |
return toolBarFrame | |
} | |
private fun setupInternal() { | |
when (config.style) { | |
ToolbarStyle.TRANSPARENT -> { | |
toolBarFrame.setBackgroundResource(android.R.color.transparent) | |
} | |
ToolbarStyle.BLACK -> { | |
toolBarFrame.setBackgroundResource(android.R.color.black) | |
} | |
ToolbarStyle.MAIN -> { | |
toolBarFrame.setBackgroundResource(R.drawable.image_bg_navigation_bar_min) | |
} | |
ToolbarStyle.MAIN_DAYNIGHT -> { | |
val bg = context.theme.obtainStyledAttributes(intArrayOf(R.attr.chatGroupToolbarBackground)).getDrawable(0) | |
toolBarFrame.setBackgroundDrawable(bg) | |
} | |
ToolbarStyle.PURPLE -> { | |
toolBarFrame.setBackgroundResource(R.color.stock_qa_main_color) | |
} | |
} | |
config.lefts?.forEach { button -> | |
if (button.action != null) { | |
showAction(button.action, button.clickHandler, Orientation.LEFT) | |
} | |
if (button.text.isNullOrEmpty().not()) { | |
setTextButtonLeft( | |
text = button.text ?: "", | |
clickHandler = button.clickHandler | |
) | |
} | |
} | |
config.rights?.forEach { button -> | |
if (button.action != null) { | |
showAction(button.action, button.clickHandler, Orientation.RIGHT) | |
} | |
if (button.text.isNullOrEmpty().not()) { | |
setTextButtonRight( | |
text = button.text ?: "", | |
textColor = button.textStyle?.color, | |
showRadiusBorder = button.showRadiusBorder, | |
clickHandler = button.clickHandler | |
) | |
} | |
} | |
config.middle.apply { | |
when (this) { | |
is ToolbarTitleConfig -> { | |
hideSearchBar() | |
setTitle(this.title) | |
} | |
is ToolbarSearchConfig -> { | |
hideTitle() | |
showSearchBar() | |
setSearchHint(this.hint) | |
setSearchEditTextOnFocusListener { this.onFocus?.invoke() } | |
setSearchEditTextCloseBtnListener { this.onClose?.invoke() } | |
setSearchEditTextChangedListener { keyword -> | |
tool_bar_search_close_button.isVisible = keyword.isNotEmpty() | |
this.onTextChange?.invoke(keyword) | |
} | |
setKeyBoardSearchListener(object: ToolBarSearchListener { | |
override fun onResult(keyword: String) { | |
onSearch?.invoke(keyword) | |
} | |
}) | |
setSearchEditTextClickListener { this.onClick?.invoke() } | |
} | |
is ToolbarImageConfig -> { | |
setImage(this.imageResId) | |
} | |
} | |
} | |
} | |
private fun showAction(action: ToolbarAction, impl: (View) -> Unit, orientation: Orientation) { | |
val view = ImageView(context).apply { | |
layoutParams = ViewGroup.LayoutParams(iconSize, iconSize) | |
setImageDrawable(context.getCompatibleDrawable(action.drawableRes)) | |
clicks() | |
.doOnNext { impl(this) } | |
.subscribe() | |
} | |
when (orientation) { | |
Orientation.LEFT -> llLeftButtonContainer.addView(view) | |
Orientation.RIGHT -> llRightButtonContainer.addView(view) | |
} | |
} | |
private fun hideAllActions() { | |
llLeftButtonContainer.removeAllViews() | |
llRightButtonContainer.removeAllViews() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment