Android使用 PopupWindow 實(shí)現(xiàn)底部彈窗功能
一、知識(shí)點(diǎn)
不詳細(xì)展開(kāi) PopupWindow 或者視圖動(dòng)畫(huà)的所有具體使用方式,僅僅介紹一下使用的一個(gè)大概流程和一些知識(shí)要點(diǎn),具體的介紹在下面設(shè)計(jì)實(shí)現(xiàn)中講述
(一)PopupWindow
1. 初始化
- 加載彈窗的布局
- 實(shí)例化 PopupWindow 傳入布局和彈窗的寬高
- 對(duì)布局里面的控件的操作
- 對(duì)布局本身的一些設(shè)置
// 加載彈窗的布局 pwView = LayoutInflater.from(this).inflate(R.layout.pw_search_engine, null, false) //實(shí)例化 PopupWindow popupWindow = PopupWindow( pwView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) // 對(duì)布局里面的控件的操作 initRecyclerView() // 對(duì)布局本身的一些設(shè)置 popupWindow.isOutsideTouchable = true popupWindow.isTouchable = true popupWindow.isFocusable = true popupWindow.animationStyle = R.style.pw_bottom_anim_style popupWindow.setOnDismissListener { backgroundAlpha(1f) }
2. 展示彈窗
彈出彈窗修改背景亮度—變暗
// 彈出彈窗 val rootView = LayoutInflater.from(this).inflate(R.layout.activity_main,null) popupWindow.showAtLocation(rootView, Gravity.BOTTOM, 0, 0) // 修改背景亮度—變暗 backgroundAlpha(0.7f)
3. 關(guān)閉彈窗
- 關(guān)閉彈窗
- 修改背景亮度—變亮
// 關(guān)閉彈窗 popupWindow.dismiss() // 修改背景亮度—變亮 backgroundAlpha(1f)
4. 背景亮度修改
// 控制背景亮度 private fun backgroundAlpha(bgAlpha: Float) { val lp = window.attributes lp.alpha = bgAlpha //0.0-1.0 window.attributes = lp }
(二)視圖動(dòng)畫(huà)
使用 XML 標(biāo)簽定義并使用視圖動(dòng)畫(huà):
1. XML 標(biāo)簽
- alpha 漸變透明度
- scale 漸變尺寸伸縮
- translate 畫(huà)面位置移動(dòng)
- rotate 畫(huà)面轉(zhuǎn)移旋轉(zhuǎn)
- set 定義動(dòng)畫(huà)集
2. 給 PopupWindow 添加動(dòng)畫(huà)
popupWindow.animationStyle = R.style.pw_bottom_anim_style
二、界面效果
三、設(shè)計(jì)實(shí)現(xiàn)
(一)需求分析
- 點(diǎn)擊主頁(yè)按鈕彈出底部彈窗
- 點(diǎn)擊彈窗引擎,以Toast顯示引擎名稱并關(guān)閉彈窗
- 點(diǎn)擊彈窗外部可以關(guān)閉彈窗
(二)文件列表
(三)布局設(shè)計(jì)
1. 主界面樣式設(shè)計(jì)
(activity_main.xml)
主界面的樣式十分簡(jiǎn)單,就是一個(gè)普通的按鈕
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context=".MainActivity"> <Button android:id="@+id/btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="14dp" android:text="點(diǎn)擊——底部彈窗" android:textColor="@color/white"/> </LinearLayout>
2. 彈窗樣式設(shè)計(jì)
(pw_search_engine.xml)
彈窗樣式的布局也十分簡(jiǎn)單,就是一個(gè)基本的線性布局的 RecyclerView
值得注意的是,最基本的 layoutManager 可以通過(guò)指定 app:layoutManager 來(lái)實(shí)現(xiàn)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="wrap_content" android:overScrollMode="never" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> </LinearLayout>
3. 彈窗列表 item 樣式設(shè)計(jì)
(item_search_engine.xml)
列表單項(xiàng),因?yàn)槭?Demo 示例,所以簡(jiǎn)單地用一個(gè)橫向布局,內(nèi)置一個(gè)圖標(biāo) icon 和一個(gè)名稱 TextView 來(lái)進(jìn)行展示
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <ImageView android:id="@+id/iconIV" android:layout_width="36dp" android:layout_height="36dp" android:layout_margin="14dp" /> <TextView android:id="@+id/titleTV" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginEnd="36dp" android:maxLines="1" android:ellipsize = "end" android:textColor="@color/black" android:textSize="16sp" /> </LinearLayout>
4. 彈窗動(dòng)畫(huà)設(shè)計(jì)
(pw_bottom_in.xml 與 pw_bottom_out.xml)
<!--pw_bottom_in.xml--> <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 平移動(dòng)畫(huà) duration--動(dòng)畫(huà)持續(xù)時(shí)間 android:fromXDelta,android:fromYDelta--起始 x,y android:toXDelta,android:toYDelta--終點(diǎn) x,y --> <translate android:duration="300" android:fromXDelta="0" android:fromYDelta="1000" android:toXDelta="0" android:toYDelta="0" /> </set> <!--pw_bottom_out.xml--> <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="300" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="1000" /> </set>
(四)數(shù)據(jù)存儲(chǔ)與加載
1. 數(shù)據(jù)存儲(chǔ)(UIData.kt 與 arrays.xml)
// 搜索引擎的數(shù)據(jù)實(shí)體類,包含名稱和 icon 資源 id 兩個(gè)屬性 data class SearchEngine( val title : String, val res : Int )
以字符串?dāng)?shù)組的形式存儲(chǔ)搜索引擎的名稱以及對(duì)應(yīng)的圖標(biāo)資源
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="search_engine_title_list"> <item>百度</item> <item>搜狗</item> <item>360</item> <item>必應(yīng)</item> <item>神馬</item> </string-array> <string-array name="search_engine_res_list"> <item>@drawable/ic_baidu</item> <item>@drawable/ic_sougou</item> <item>@drawable/ic_360</item> <item>@drawable/ic_bing</item> <item>@drawable/ic_shenma</item> </string-array> </resources>
2. 數(shù)據(jù)加載(MainActivity.kt)
private lateinit var engines : MutableList<SearchEngine> private fun initData() { // 初始化引擎列表 engines = mutableListOf() // 從 arrays.xml 獲取引擎名稱數(shù)組 val titleList = resources.getStringArray(R.array.search_engine_title_list) // 由于資源 id 是整型,但是在 arrays.xml 中存儲(chǔ)的是字符串, // 所以這里先初始化一個(gè)資源 id 的數(shù)組,元素類型為整型 val iconResList : MutableList<Int> = mutableListOf() // 通過(guò)類型數(shù)組加載相關(guān)引擎資源列表,遍歷其中元素,傳入索引值, // 通過(guò)調(diào)用 getResourceId(index,0) 獲取 icon 的資源 id 存入剛才初始化的 id 數(shù)組中 val resList: TypedArray = resources.obtainTypedArray(R.array.search_engine_res_list) for (index in 0 until resList.length()) { iconResList.add(resList.getResourceId(index,0)) } // 記得及時(shí)調(diào)用 recycle() 回收 TypedArray 對(duì)象 resList.recycle() // 循環(huán),用獲得的 title 和 id 生成對(duì)應(yīng)的搜索引擎對(duì)象,存入搜索引擎列表中 for (index in titleList.indices){ if (index < iconResList.size){ engines.add(SearchEngine(titleList[index],iconResList[index])) } } }
(五)剩余內(nèi)容
上述提及的內(nèi)容代碼,此處將不再進(jìn)行展示;因?yàn)橹攸c(diǎn)是介紹底部彈窗的實(shí)現(xiàn),彈窗布局中的 RecyclerView 的實(shí)現(xiàn)就不過(guò)多介紹
1. AdapterForSearchEngine.kt 彈窗列表適配器
class AdapterForSearchEngine (dataList: MutableList<SearchEngine>) : RecyclerView.Adapter<AdapterForSearchEngine.ViewHolder>() { // 搜索引擎數(shù)據(jù)集合 private val mDataList: MutableList<SearchEngine> = mutableListOf() init { // 初始化 主要是對(duì)數(shù)據(jù)進(jìn)行初始化 mDataList.clear() mDataList.addAll(dataList) } // ViewHolder 方便 item 復(fù)用 class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {} // 獲取列表 item 數(shù)量 override fun getItemCount(): Int { return mDataList.size } // 綁定視圖與數(shù)據(jù) override fun onBindViewHolder(holder: ViewHolder, position: Int) { val engine: SearchEngine = mDataList[position] holder.itemView.titleTV.text = engine.title holder.itemView.iconIV.setImageResource(engine.res) holder.itemView.setOnClickListener { listener?.click(engine) } } // 創(chuàng)建 ViewHolder 實(shí)例 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view: View = LayoutInflater.from(parent.context).inflate(R.layout.item_search_engine, parent, false) return ViewHolder(view) } // 點(diǎn)擊事件 private var listener :OnItemClickListener? = null interface OnItemClickListener { fun click(engine: SearchEngine) } fun setOnItemClickListener(listener: OnItemClickListener) { this.listener = listener } }
2. MainActivity.kt
class MainActivity : AppCompatActivity() { private lateinit var engines : MutableList<SearchEngine> private lateinit var popupWindow : PopupWindow private lateinit var pwView : View private lateinit var mAdapter : AdapterForSearchEngine override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化數(shù)據(jù) initData() // 初始化 PopupWindow initPopupWindow() // 按鈕點(diǎn)擊事件 btn.setOnClickListener { // 顯示彈窗 showPopWindow() } } private fun initPopupWindow() { // 加載彈窗布局 pwView = LayoutInflater.from(this).inflate(R.layout.pw_search_engine, null, false) // 實(shí)例化 PopupWindow popupWindow = PopupWindow( pwView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) // 初始化彈窗列表 initRecyclerView() // 設(shè)置 popupWindow popupWindow.isOutsideTouchable = true popupWindow.isTouchable = true popupWindow.isFocusable = true // 加載彈窗動(dòng)畫(huà) popupWindow.animationStyle = R.style.pw_bottom_anim_style // 設(shè)置彈窗關(guān)閉監(jiān)聽(tīng)——恢復(fù)亮度 popupWindow.setOnDismissListener { backgroundAlpha(1f) } } private fun showPopWindow() { val rootView = LayoutInflater.from(this).inflate( R.layout.activity_main, null ) // 設(shè)置彈窗位置 popupWindow.showAtLocation(rootView, Gravity.BOTTOM, 0, 0) // 使得背景亮度變暗 backgroundAlpha(0.7f) } // 控制背景亮度 private fun backgroundAlpha(bgAlpha: Float) { val lp = window.attributes lp.alpha = bgAlpha //0.0-1.0 window.attributes = lp } private fun initRecyclerView() { mAdapter = AdapterForSearchEngine(engines) pwView.recyclerView?.adapter = mAdapter mAdapter.setOnItemClickListener(object : AdapterForSearchEngine.OnItemClickListener{ override fun click(engine: SearchEngine) { Toast.makeText(this@MainActivity, engine.title, Toast.LENGTH_SHORT).show() popupWindow.dismiss() } }) } private fun initData() { // 初始化引擎列表 engines = mutableListOf() // 從 arrays.xml 獲取引擎名稱數(shù)組 val titleList = resources.getStringArray(R.array.search_engine_title_list) // 由于資源 id 是整型,但是在 arrays.xml 中存儲(chǔ)的是字符串, // 所以這里先初始化一個(gè)資源 id 的數(shù)組,元素類型為整型 val iconResList : MutableList<Int> = mutableListOf() // 通過(guò)類型數(shù)組加載相關(guān)引擎資源列表,遍歷其中元素,傳入索引值, // 通過(guò)調(diào)用 getResourceId(index,0) 獲取 icon 的資源 id 存入剛才初始化的 id 數(shù)組中 val resList: TypedArray = resources.obtainTypedArray(R.array.search_engine_res_list) for (index in 0 until resList.length()) { iconResList.add(resList.getResourceId(index,0)) } // 記得及時(shí)調(diào)用 recycle() 回收 TypedArray 對(duì)象 resList.recycle() // 循環(huán),用獲得的 title 和 id 生成對(duì)應(yīng)的搜索引擎對(duì)象,存入搜索引擎列表中 for (index in titleList.indices){ if (index < iconResList.size){ engines.add(SearchEngine(titleList[index],iconResList[index])) } } } }
到此這篇關(guān)于Android使用 PopupWindow 實(shí)現(xiàn)底部彈窗功能的文章就介紹到這了,更多相關(guān)Android PopupWindow底部彈窗內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android開(kāi)發(fā)之PopupWindow實(shí)現(xiàn)彈窗效果
- Android彈窗ListPopupWindow的簡(jiǎn)單應(yīng)用詳解
- Android PopupWindow實(shí)現(xiàn)左側(cè)彈窗效果
- Android開(kāi)發(fā)實(shí)現(xiàn)popupWindow彈出窗口自定義布局與位置控制方法
- Android Popupwindow彈出窗口的簡(jiǎn)單使用方法
- Android編程實(shí)現(xiàn)的自定義彈窗(PopupWindow)功能示例
- Android自定義彈出窗口PopupWindow使用技巧
- Android控件PopupWindow模仿ios底部彈窗
- android PopupWindow 和 Activity彈出窗口實(shí)現(xiàn)方式
- Android中PopupWindow彈出式窗口使用方法詳解
相關(guān)文章
Android使用DrawerLayout實(shí)現(xiàn)仿QQ雙向側(cè)滑菜單
這篇文章主要介紹了Android使用DrawerLayout實(shí)現(xiàn)仿QQ雙向側(cè)滑菜單的方法和詳細(xì)代碼,有需要的小伙伴可以認(rèn)真參考下。2016-01-01關(guān)于Android中自定義ClassLoader耗時(shí)問(wèn)題的追查
熱修復(fù)和插件化是目前比較熱門(mén)的技術(shù),要想更好的掌握它們需要了解ClassLoader,下面這篇文章主要給大家介紹了關(guān)于Android中自定義ClassLoader耗時(shí)問(wèn)題追查的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧2018-06-06Android賬號(hào)注冊(cè)實(shí)現(xiàn)點(diǎn)擊獲取驗(yàn)證碼倒計(jì)時(shí)效果
這篇文章主要為大家詳細(xì)介紹了Android賬號(hào)注冊(cè)過(guò)程中實(shí)現(xiàn)點(diǎn)擊獲取驗(yàn)證碼倒計(jì)時(shí)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05Android自定義ViewPager實(shí)現(xiàn)縱向滑動(dòng)翻頁(yè)效果
這篇文章主要為大家詳細(xì)介紹了Android自定義ViewPager實(shí)現(xiàn)縱向滑動(dòng)翻頁(yè)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android仿微信發(fā)表說(shuō)說(shuō)實(shí)現(xiàn)拍照、多圖上傳功能
這篇文章主要為大家詳細(xì)介紹了Android仿微信發(fā)表說(shuō)說(shuō)實(shí)現(xiàn)拍照、多圖上傳功能,使用Retrofit2.0技術(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-03-03Android啟動(dòng)屏實(shí)現(xiàn)左右滑動(dòng)切換查看功能
這篇文章主要介紹了Android啟動(dòng)屏實(shí)現(xiàn)左右滑動(dòng)切換查看功能的相關(guān)資料,針對(duì)新功能屬性介紹和啟動(dòng)屏進(jìn)行詳細(xì)講解,感興趣的小伙伴們可以參考一下2016-01-01Android中Activity的四種啟動(dòng)模式和onNewIntent()
android 中activity的啟動(dòng)模式分為四種,(standard、singleTop、singTask、singleInstance),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-08-08Android?Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器開(kāi)發(fā)
這篇文章主要為大家詳細(xì)介紹了Android?Studio實(shí)現(xiàn)簡(jiǎn)單計(jì)算器開(kāi)發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05Android studio 運(yùn)行main 函數(shù)的方法
這篇文章主要介紹了Android studio 運(yùn)行main 函數(shù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Android仿IOS10圓盤(pán)時(shí)間選擇器
這篇文章主要為大家詳細(xì)介紹了Android仿IOS10圓盤(pán)時(shí)間選擇器,自定義圓盤(pán)時(shí)間選擇器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07