aboutsummaryrefslogtreecommitdiff
path: root/library/src/main/kotlin/ca/allanwang
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/main/kotlin/ca/allanwang')
-rw-r--r--library/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt113
1 files changed, 63 insertions, 50 deletions
diff --git a/library/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt b/library/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt
index 8ffc871..4449fe5 100644
--- a/library/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt
+++ b/library/src/main/kotlin/ca/allanwang/kau/searchview/SearchView.kt
@@ -8,10 +8,7 @@ import android.support.v7.widget.CardView
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.AttributeSet
-import android.view.Menu
-import android.view.MenuItem
-import android.view.View
-import android.view.ViewGroup
+import android.view.*
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.ProgressBar
@@ -22,6 +19,7 @@ import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.mikepenz.iconics.typeface.IIcon
+
/**
* Created by Allan Wang on 2017-06-23.
*/
@@ -29,19 +27,9 @@ class SearchView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
- companion object {
- fun bind(parent: ViewGroup, menu: Menu, @IdRes id: Int, config: Configs.() -> Unit = {}) {
- SearchView(parent.context).apply {
- layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
- parent.addView(this)
- this.bind(parent, menu, id, config)
- }
- }
- }
-
//configs
inner class Configs {
- var foregroundColor: Int = 0xddffffff.toInt()
+ var foregroundColor: Int = 0xdd000000.toInt()
set(value) {
if (field == value) return
field = value
@@ -56,51 +44,52 @@ class SearchView @JvmOverloads constructor(
var navIcon: IIcon? = GoogleMaterial.Icon.gmd_arrow_back
set(value) {
field = value
- iconNav.setIcon(value)
+ iconNav.setSearchIcon(value)
if (value == null) iconNav.gone()
}
var micIcon: IIcon? = GoogleMaterial.Icon.gmd_mic
set(value) {
field = value
- iconMic.setIcon(value)
+ iconMic.setSearchIcon(value)
if (value == null) iconMic.gone()
}
var clearIcon: IIcon? = GoogleMaterial.Icon.gmd_clear
set(value) {
field = value
- iconClear.setIcon(value)
+ iconClear.setSearchIcon(value)
if (value == null) iconClear.gone()
}
var revealDuration: Long = 300L
var shouldClearOnOpen: Boolean = true
- var openListener: (() -> Unit)? = null
- var closeListener: (() -> Unit)? = null
+ var openListener: ((searchView: SearchView) -> Unit)? = null
+ var closeListener: ((searchView: SearchView) -> Unit)? = null
}
val configs = Configs()
//views
- private val shadow: View by bindView(R.id.search_shadow)
- private val card: CardView by bindView(R.id.search_cardview)
- private val iconNav: ImageView by bindView(R.id.search_nav)
- private val editText: AppCompatEditText by bindView(R.id.search_edit_text)
- private val progress: ProgressBar by bindView(R.id.search_progress)
- private val iconMic: ImageView by bindView(R.id.search_mic)
- private val iconClear: ImageView by bindView(R.id.search_clear)
- private val recycler: RecyclerView by bindView(R.id.search_recycler)
- private val adapter = FastItemAdapter<SearchItem>()
- private lateinit var parent: ViewGroup
+ val shadow: View by bindView(R.id.search_shadow)
+ val card: CardView by bindView(R.id.search_cardview)
+ val iconNav: ImageView by bindView(R.id.search_nav)
+ val editText: AppCompatEditText by bindView(R.id.search_edit_text)
+ val progress: ProgressBar by bindView(R.id.search_progress)
+ val iconMic: ImageView by bindView(R.id.search_mic)
+ val iconClear: ImageView by bindView(R.id.search_clear)
+ val recycler: RecyclerView by bindView(R.id.search_recycler)
+ val adapter = FastItemAdapter<SearchItem>()
+ lateinit var parent: ViewGroup
val isOpen: Boolean
get() = card.isVisible()
//menu view
- private var revealX: Int = -1
- private var revealY: Int = -1
+ var menuX: Int = -1
+ var menuY: Int = -1
+ var menuHalfHeight: Int = -1
init {
View.inflate(context, R.layout.kau_search_view, this)
- iconNav.setIcon(configs.navIcon)
- iconMic.setIcon(configs.micIcon)
- iconClear.setIcon(configs.clearIcon)
+ iconNav.setSearchIcon(configs.navIcon)
+ iconMic.setSearchIcon(configs.micIcon)
+ iconClear.setSearchIcon(configs.clearIcon)
tintForeground(configs.foregroundColor)
tintBackground(configs.backgroundColor)
with(recycler) {
@@ -115,15 +104,15 @@ class SearchView @JvmOverloads constructor(
}
}
- internal fun ImageView.setSearchIcon(iicon: IIcon) {
- setIcon(iicon, sizeDp = 20, color = configs.foregroundColor)
+ internal fun ImageView.setSearchIcon(iicon: IIcon?) {
+ setIcon(iicon, sizeDp = 18, color = configs.foregroundColor)
}
fun config(config: Configs.() -> Unit) {
configs.config()
}
- fun bind(parent: ViewGroup, menu: Menu, @IdRes id: Int, config: Configs.() -> Unit = {}) {
+ fun bind(parent: ViewGroup, menu: Menu, @IdRes id: Int, config: Configs.() -> Unit = {}): SearchView {
config(config)
this.parent = parent
val item = menu.findItem(id)
@@ -131,19 +120,30 @@ class SearchView @JvmOverloads constructor(
card.gone()
item.setOnMenuItemClickListener { configureCoords(it); revealOpen(); true }
shadow.setOnClickListener { revealClose() }
+ return this
}
fun configureCoords(item: MenuItem) {
val view = parent.findViewById<View>(item.itemId) ?: return
val locations = IntArray(2)
view.getLocationOnScreen(locations)
- revealX = (locations[0] + view.width / 2)
- revealY = (locations[1] + view.height / 2)
- val topAlignment = revealY - card.height / 2
- val params = (card.layoutParams as MarginLayoutParams).apply {
- topMargin = topAlignment
- }
- card.layoutParams = params
+ menuX = (locations[0] + view.width / 2)
+ menuHalfHeight = view.height / 2
+ menuY = (locations[1] + menuHalfHeight)
+ card.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
+ override fun onPreDraw(): Boolean {
+ view.viewTreeObserver.removeOnPreDrawListener(this)
+ with(card) {
+ KL.e("S $width $measuredWidth $height $measuredHeight")
+ }
+ val topAlignment = menuY - card.height / 2
+ val params = (card.layoutParams as MarginLayoutParams).apply {
+ topMargin = topAlignment
+ }
+ card.layoutParams = params
+ return false
+ }
+ })
}
fun tintForeground(@ColorInt color: Int) {
@@ -159,9 +159,14 @@ class SearchView @JvmOverloads constructor(
fun revealOpen() {
if (isOpen) return
- card.circularReveal(revealX, revealY, duration = configs.revealDuration,
+ /**
+ * The y component is relative to the cardView, but it hasn't been drawn yet so its own height is 0
+ * We therefore use half the menuItem height, which is a close approximation to our intended value
+ * The cardView matches the parent's width, so menuX is correct
+ */
+ card.circularReveal(menuX, menuHalfHeight, duration = configs.revealDuration,
onStart = {
- configs.openListener?.invoke()
+ configs.openListener?.invoke(this)
if (configs.shouldClearOnOpen) editText.text.clear()
},
onFinish = {
@@ -173,10 +178,18 @@ class SearchView @JvmOverloads constructor(
fun revealClose() {
if (!isOpen) return
shadow.fadeOut() {
- card.circularHide(revealX, revealY, duration = configs.revealDuration,
+ card.circularHide(menuX, menuHalfHeight, duration = configs.revealDuration,
onFinish = {
- configs.closeListener?.invoke()
+ configs.closeListener?.invoke(this)
})
}
}
-} \ No newline at end of file
+}
+
+fun ViewGroup.bindSearchView(menu: Menu, @IdRes id: Int, config: SearchView.Configs.() -> Unit = {}): SearchView {
+ val searchView = SearchView(context)
+ searchView.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)
+ addView(searchView)
+ searchView.bind(this, menu, id, config)
+ return searchView
+}