Android 三級列表選擇器 (地址選擇器)

關于PopupWindow迹淌,首先要解決popupwindow在Android7.0顯示錯誤的問題

open class PopupWindowV24 : PopupWindow {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
    constructor() : super()
    constructor(contentView: View?) : super(contentView)
    constructor(width: Int, height: Int) : super(width, height)
    constructor(contentView: View?, width: Int, height: Int) : super(contentView, width, height)
    constructor(contentView: View?, width: Int, height: Int, focusable: Boolean) : super(contentView, width, height, focusable)

    override fun showAsDropDown(anchor: View) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
            val rect = Rect()
            anchor.getGlobalVisibleRect(rect)
            val h = anchor.resources.displayMetrics.heightPixels - rect.bottom
            height = h
        }
        super.showAsDropDown(anchor)
    }
}
WechatIMG14.jpeg

然后,我們需要先寫一個類似京東地址選擇的xml己单,因為radioGroup可以方便監(jiān)聽選擇狀態(tài)唉窃,而且可以復用recyclerview,

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <!-- 陰影區(qū) -->
    <View
        android:id="@+id/backgroundView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@color/black"
        android:alpha="0.5"
        <!-- 這里不是在titleCl而是tabRg是為了控制圓角效果 -->
        app:layout_constraintBottom_toTopOf="@id/tabRg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <!-- 用來添加背景 -->
    <View
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/bg_popupwindow_radius"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/titleCl" />
    <!-- 頂部title和取消 -->
    <android.support.constraint.ConstraintLayout
        android:id="@+id/titleCl"
        android:layout_width="0dp"
        android:layout_height="65dp"
        android:layout_marginBottom="10dp"
        app:layout_constraintBottom_toTopOf="@id/tabRg"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <TextView
            android:id="@+id/titleTv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#333333"
            android:textSize="18dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>

        <ImageView
            android:id="@+id/cancelTv"
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:layout_marginEnd="20dp"
            android:gravity="center"
            android:paddingStart="20dp"
            android:paddingEnd="20dp"
            android:background="@drawable/close_drawable"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </android.support.constraint.ConstraintLayout>
    <!-- 選擇器頂部的tab -->
    <RadioGroup
        android:id="@+id/tabRg"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toTopOf="@id/contentLl"
        app:layout_constraintStart_toStartOf="parent">

        <RadioButton
            android:id="@+id/firstRb"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginStart="20dp"
            android:button="@null"
            android:paddingTop="10dp"
            android:gravity="center_horizontal"
            android:text="請選擇"
            android:maxLines="1"
            android:ellipsize="end"
            android:checked="true"
            android:textColor="#333333"
            android:textSize="13dp"
            tools:checked="true" />

        <RadioButton
            android:id="@+id/secondRb"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginStart="25dp"
            android:button="@null"
            android:maxLines="1"
            android:ellipsize="end"
            android:paddingTop="10dp"
            android:visibility="gone"
            android:gravity="center_horizontal"
            android:text="請選擇"
            android:textColor="#333333"
            android:textSize="13dp" />

        <RadioButton
            android:id="@+id/thridRb"
            android:layout_marginStart="25dp"
            android:layout_width="wrap_content"
            android:button="@null"
            android:maxLines="1"
            android:visibility="gone"
            android:ellipsize="end"
            android:paddingTop="10dp"
            android:gravity="center_horizontal"
            android:text="請選擇"
            android:textColor="#333333"
            android:textSize="13dp"
            android:layout_height="match_parent" />

    </RadioGroup>

    <android.support.constraint.ConstraintLayout
        android:id="@+id/contentLl"
        android:layout_width="0dp"
        android:layout_height="400dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/listItemRv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    </android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

分析一些三級選擇器的參數(shù)纹笼,我們需要一個標題title纹份,一個數(shù)據(jù)源dataSource,一個選擇完成的回調,注意這里的數(shù)據(jù)源可以根據(jù)實際情況進行修改蔓涧,不一定非要傳三個list件已。

class ThirdLevelListPopupWindow(
        private val context: Context,
        private val title: String = "標題",
        private val dataSource: () -> ThirdLevelListDataModel,
        private val commitCallback: (param1: String,param2: Sting,param3: String) -> Unit
) : PopupWindowV24(context) {
    ...
}

分析一下這個三級列表的屬性,首先元暴,因為是三級列表篷扩,所以一定是每一級都依賴上一級的選擇來進行聯(lián)動,所以需要監(jiān)聽每次RecyclerView的點擊位置茉盏。
同時鉴未,我們要根據(jù)點擊的item來設置頂部tab的文字內容,所以需要在數(shù)據(jù)源中取出item中的數(shù)據(jù)鸠姨,默認賦值為-1來表示初始化沒有選擇item的情況铜秆。

    private var firstList: ArrayList<String> = ArrayList()
    private var secondList: ArrayList<String> = ArrayList()
    private var thirdList: ArrayList<String> = ArrayList()

    private var firstIndex = -1
    set(value) {
        field = value
        if (value == -1) {
            firstRb.text = "請選擇"
        } else {
            firstRb.text = firstList[value]
        }
    }

    private var secondIndex = -1
    set(value) {
        field = value
        if (value == -1) {
            secondRb.text = "請選擇"
        } else {
            secondRb.text = secondList[value]
        }
    }


    private var thirdIndex = -1
    set(value) {
        field = value
        if (value == -1) {
            thirdRb.text = "請選擇"
        } else {
            thirdRb.text = thirdList[value]
        }
    }

我們還需要一個標記來判斷當前選中的tab:

private var curTabPosition : Int = 0

接下來我們要對RecyclerView的adapter進行設計,我們需要傳入一個List數(shù)據(jù)源讶迁,一個選中位置的標記连茧,還有一個選擇item的點擊閉包。
由于我們復用了同一個recyclerView巍糯,所以當我們選擇不同tab的時候梅屉,要更改對應的數(shù)據(jù)源,需要在外部更改數(shù)據(jù)源鳞贷、點擊事件、和選擇item的位置虐唠,所以我們用閉包來在外部控制數(shù)據(jù)搀愧。

class ThirdLevelListPopupWindowAdapter(
        private val dataSource : () -> List<String>,
        val isSelectedBlock: (Int) -> Boolean,
        val block: (Int) -> Unit)
: RecyclerView.Adapter<AddressListPopupWindowAdapter.ViewHolder>() {
    ...
}

其中item的點擊事件在onBindViewHolder()中進行設置

        holder.itemView.setOnClickListener{
            block.invoke(position)
        }

在ThirdLevelListPopupWindow中初始化這個adapter:

adapter = ThirdLevelListPopupWindowAdapter({
            when (curTabPosition) {
                0 -> firstList
                1 -> secondList
                else -> thirdList
            }
        }, {
            when (curTabPosition) {
                0 -> it == firstIndex
                1 -> it == secondIndex
                else -> it == thirdIndex
            }
        },{
            when (curTabPosition) {
                0 -> setFirstTab(it)
                1 -> setSceondTab(it)
                else -> setThirdTab(it)
            }
        })

將adapter綁定到RecyclerView之后,為三個tab設置點擊事件疆偿,

         firstRb.setOnClickListener {
            firstRb.isChecked = true
            curTabPosition = 0
            adapter.notifyDataSetChanged()
        }
        secondRb.setOnClickListener {
            secondRb.isChecked = true
            curTabPosition = 1
            adapter.notifyDataSetChanged()
        }
        thirdRb.setOnClickListener {
            thirdRb.isChecked = true
            curTabPosition = 2
            adapter.notifyDataSetChanged()
        }

每一級的RecyclerView的點擊事件

    private fun setFirstTab(position: Int) {
        firstIndex = position
        firstRb.text = firstList[position]
        secondRb.visibility = View.VISIBLE
        secondRb.text = "請選擇"
        secondIndex = -1
        secondRb.isChecked= true
        secondList.clear()
        initData(secondList)    //這里方法根據(jù)自己的實際情況去實現(xiàn)即可
        thirdIndex = -1
        thirdRb.visibility = View.GONE
        curTabPosition = 1
        adapter.notifyDataSetChanged()
    }

    private fun setSecondTab(position: Int) {
        curTabPosition = 2
        thirdIndex = -1
        thirdList.clear()
        initData(thirdList)
        thirdRb.visibility = View.VISIBLE
        thirdRb.isChecked = true
        thirdRb.text = "請選擇"
        secondIndex = position
        adapter.notifyDataSetChanged()
    }

    private fun setSecondTab(position: Int) {
        thridIndex = position
        commitCallback.invoke(firstList[firstIndex], secondList[secondIndex], thirdList[thirdIndex])
        dismiss()
    }
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末咱筛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子杆故,更是在濱河造成了極大的恐慌迅箩,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件处铛,死亡現(xiàn)場離奇詭異饲趋,居然都是意外死亡,警方通過查閱死者的電腦和手機撤蟆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門奕塑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人家肯,你說我怎么就攤上這事龄砰。” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵换棚,是天一觀的道長式镐。 經(jīng)常有香客問我,道長固蚤,這世上最難降的妖魔是什么娘汞? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮颇蜡,結果婚禮上价说,老公的妹妹穿的比我還像新娘。我一直安慰自己风秤,他們只是感情好鳖目,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缤弦,像睡著了一般领迈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碍沐,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天狸捅,我揣著相機與錄音,去河邊找鬼累提。 笑死尘喝,一個胖子當著我的面吹牛,可吹牛的內容都是我干的斋陪。 我是一名探鬼主播朽褪,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼无虚!你這毒婦竟也來了缔赠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤友题,失蹤者是張志新(化名)和其女友劉穎嗤堰,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體度宦,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡踢匣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了戈抄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片符糊。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呛凶,靈堂內的尸體忽然破棺而出男娄,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布模闲,位于F島的核電站建瘫,受9級特大地震影響,放射性物質發(fā)生泄漏尸折。R本人自食惡果不足惜啰脚,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望实夹。 院中可真熱鬧橄浓,春花似錦、人聲如沸亮航。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缴淋。三九已至准给,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間重抖,已是汗流浹背露氮。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钟沛,地道東北人畔规。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像恨统,于是被迫代替她去往敵國和親油讯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容