332일차 - Custom BottomNavigaion (2)

2021. 12. 2. 19:39Diary/300~400

완성했다.

간단하게 XML로 사용하면서

가장 필요한 기능인

어느 화면으로 전환할지에 대한

액션 값을 받아오게끔 했다.

 

 

< BottomNavigationItem >

package navigation

import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
import android.content.res.XmlResourceParser
import android.graphics.Color
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.Checkable
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import com.kwon.mywidgetcollection.R

class BottomNavigationItem(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs), Checkable {
    lateinit var action: String
    lateinit var imageView: AppCompatImageView
    lateinit var textView:AppCompatTextView
    private lateinit var defaultColor: String
    private lateinit var focusColor: String
    private lateinit var disableColor: String
    private val Int.dp: Int get() = (this * Resources.getSystem().displayMetrics.density + 0.5f).toInt()

    init {
        context?.let { con ->
            attrs?.let { attr ->
                initAttrs(con, attr)
            }
        }
    }

    private fun initAttrs(context: Context, attrs: AttributeSet) {
        orientation = VERTICAL
        gravity = Gravity.CENTER

        context.obtainStyledAttributes(attrs, R.styleable.BottomNavigationItem)?.let { typedArray ->
            action = typedArray.getString(R.styleable.BottomNavigationItem_nv_action)!!

            imageView = AppCompatImageView(context)
            with(imageView) {
                val layout = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1f)
                layout.setMargins(0, 0, 0, 4.dp)
                layoutParams = layout
                adjustViewBounds = true
                setImageResource(typedArray.getResourceId(R.styleable.BottomNavigationItem_nv_image_src, 0))
                setBackgroundColor(Color.TRANSPARENT)
                isClickable = false
                addView(this)
            }

            textView = AppCompatTextView(context)
            with(textView) {
                layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
                textAlignment = TextView.TEXT_ALIGNMENT_CENTER
                textView.includeFontPadding = false
                typedArray.getString(R.styleable.BottomNavigationItem_nv_text)?.let {
                    text = it
                }
                addView(textView)
            }

            typedArray.recycle()
        }

    }

    fun itemInit(view: BottomNavigationItem) {
        view.isChecked = false
    }

    fun setTextStyle(id:Int) {
        textView.setTextAppearance(id)
    }

    fun setItemSelector(id: Int) {
        parseXml(resources.getXml(id))
    }

    private fun parseXml(parser: XmlResourceParser) {
        var eventType = -1
        val namespace = "http://schemas.android.com/apk/res/android"

        while (eventType != XmlResourceParser.END_DOCUMENT) {
            if (eventType == XmlResourceParser.START_TAG) {
                if (parser.name == "item") {
                    val stateFocused: String? = parser.getAttributeValue(namespace, "state_focused")
                    val stateEnabled: String? = parser.getAttributeValue(namespace, "state_enabled")
                    val color = resources.getString(parser.getAttributeResourceValue(namespace, "drawable", 0))
                    if(stateFocused != null) {
                        if(stateFocused == "true") focusColor = color else defaultColor = color
                    }
                    if(stateEnabled != null) {
                       disableColor = color
                    }
                }
            }
            eventType = parser.next()
        }
    }

    interface OnCheckedChangeListener {
        fun onCheckedChanged(checkableView: View?, isChecked: Boolean)
    }

    private val checkedStateSet = intArrayOf(android.R.attr.state_checked)
    private var mChecked = false
    private var mOnCheckedChangeListener: OnCheckedChangeListener? = null

    override fun isChecked(): Boolean {
        return mChecked
    }

    override fun setChecked(checked: Boolean) {
        if (checked != mChecked) {
            if(checked) {
                imageView.imageTintList = ColorStateList.valueOf(Color.parseColor(focusColor))
                textView.setTextColor(Color.parseColor(focusColor))
            } else {
                imageView.imageTintList = ColorStateList.valueOf(Color.parseColor(defaultColor))
                textView.setTextColor(Color.parseColor(defaultColor))
            }
            mChecked = checked
            refreshDrawableState()
            if (mOnCheckedChangeListener != null) {
                mOnCheckedChangeListener!!.onCheckedChanged(this, mChecked)
            }
        }
    }

    override fun toggle() {
        isChecked = !mChecked
    }

    override fun onCreateDrawableState(extraSpace: Int): IntArray? {
        val drawableState = super.onCreateDrawableState(extraSpace + 1)
        if (isChecked) {
            mergeDrawableStates(drawableState, checkedStateSet)
        }
        return drawableState
    }

    fun setOnCheckedChangeListener(listener: OnCheckedChangeListener?) {
        mOnCheckedChangeListener = listener
    }
}

 

< XML >

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/main_frag"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/main_nav"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">
    </FrameLayout>

    <navigation.BottomNavigationContainer
        android:id="@+id/main_nav"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="#ffffff"
        app:nv_text_styles="@style/bottom_nav_text"
        app:nv_item_selector="@drawable/checkable_bottom_nav"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        >

        <navigation.BottomNavigationItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:nv_image_src="@drawable/bottom_life_record"
            app:nv_text="@string/life_record"
            app:nv_action="@string/action_test"
            />

        <navigation.BottomNavigationItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:nv_image_src="@drawable/bottom_record"
            app:nv_text="@string/record"
            app:nv_action="@string/action_record"
            />

        <navigation.BottomNavigationItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:nv_image_src="@drawable/bottom_home"
            app:nv_text="@string/home"
            app:nv_action="@string/action_home"
            />

        <navigation.BottomNavigationItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:nv_image_src="@drawable/bottom_calendar"
            app:nv_text="@string/calendar"
            app:nv_action="@string/action_calendar"
            />

        <navigation.BottomNavigationItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:nv_image_src="@drawable/bottom_exam"
            app:nv_text="@string/exam"
            app:nv_action="@string/action_exam"
            />


    </navigation.BottomNavigationContainer>

</androidx.constraintlayout.widget.ConstraintLayout>