Android使用 PopupWindow 實現(xiàn)底部彈窗功能
不詳細(xì)展開 PopupWindow 或者視圖動畫的所有具體使用方式,僅僅介紹一下使用的一個大概流程和一些知識要點,具體的介紹在下面設(shè)計實現(xiàn)中講述
(一)PopupWindow1. 初始化
加載彈窗的布局 實例化 PopupWindow 傳入布局和彈窗的寬高 對布局里面的控件的操作 對布局本身的一些設(shè)置// 加載彈窗的布局pwView = LayoutInflater.from(this).inflate(R.layout.pw_search_engine, null, false)//實例化 PopupWindowpopupWindow = PopupWindow( pwView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)// 對布局里面的控件的操作initRecyclerView()// 對布局本身的一些設(shè)置popupWindow.isOutsideTouchable = truepopupWindow.isTouchable = truepopupWindow.isFocusable = truepopupWindow.animationStyle = R.style.pw_bottom_anim_stylepopupWindow.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}(二)視圖動畫
使用 XML 標(biāo)簽定義并使用視圖動畫:
1. XML 標(biāo)簽
alpha 漸變透明度 scale 漸變尺寸伸縮 translate 畫面位置移動 rotate 畫面轉(zhuǎn)移旋轉(zhuǎn) set 定義動畫集2. 給 PopupWindow 添加動畫
popupWindow.animationStyle = R.style.pw_bottom_anim_style二、界面效果
1. 主界面樣式設(shè)計
(activity_main.xml)
主界面的樣式十分簡單,就是一個普通的按鈕
<?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: android:layout_width='match_parent' android:layout_height='wrap_content' android:layout_margin='14dp' android:text='點擊——底部彈窗' android:textColor='@color/white'/></LinearLayout>
2. 彈窗樣式設(shè)計
(pw_search_engine.xml)
彈窗樣式的布局也十分簡單,就是一個基本的線性布局的 RecyclerView值得注意的是,最基本的 layoutManager 可以通過指定 app:layoutManager 來實現(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: android:layout_width='match_parent' android:layout_height='wrap_content' android:overScrollMode='never' app:layoutManager='androidx.recyclerview.widget.LinearLayoutManager' /></LinearLayout>
3. 彈窗列表 item 樣式設(shè)計
(item_search_engine.xml)
列表單項,因為是 Demo 示例,所以簡單地用一個橫向布局,內(nèi)置一個圖標(biāo) icon 和一個名稱 TextView 來進(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: android:layout_width='36dp' android:layout_height='36dp' android:layout_margin='14dp' /> <TextView android: 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. 彈窗動畫設(shè)計
(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'> <!-- 平移動畫 duration--動畫持續(xù)時間 android:fromXDelta,android:fromYDelta--起始 x,y android:toXDelta,android:toYDelta--終點 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ù)存儲與加載
1. 數(shù)據(jù)存儲(UIData.kt 與 arrays.xml)
// 搜索引擎的數(shù)據(jù)實體類,包含名稱和 icon 資源 id 兩個屬性data class SearchEngine( val title : String, val res : Int)
以字符串?dāng)?shù)組的形式存儲搜索引擎的名稱以及對應(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 中存儲的是字符串,// 所以這里先初始化一個資源 id 的數(shù)組,元素類型為整型 val iconResList : MutableList<Int> = mutableListOf() // 通過類型數(shù)組加載相關(guān)引擎資源列表,遍歷其中元素,傳入索引值, // 通過調(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)) } // 記得及時調(diào)用 recycle() 回收 TypedArray 對象 resList.recycle()// 循環(huán),用獲得的 title 和 id 生成對應(yīng)的搜索引擎對象,存入搜索引擎列表中 for (index in titleList.indices){ if (index < iconResList.size){ engines.add(SearchEngine(titleList[index],iconResList[index])) } }}(五)剩余內(nèi)容
上述提及的內(nèi)容代碼,此處將不再進(jìn)行展示;因為重點是介紹底部彈窗的實現(xiàn),彈窗布局中的 RecyclerView 的實現(xiàn)就不過多介紹
1. AdapterForSearchEngine.kt 彈窗列表適配器
class AdapterForSearchEngine (dataList: MutableList<SearchEngine>) : RecyclerView.Adapter<AdapterForSearchEngine.ViewHolder>() { // 搜索引擎數(shù)據(jù)集合 private val mDataList: MutableList<SearchEngine> = mutableListOf() init { // 初始化 主要是對數(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 實例 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) } // 點擊事件 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() // 按鈕點擊事件 btn.setOnClickListener { // 顯示彈窗 showPopWindow() } } private fun initPopupWindow() { // 加載彈窗布局 pwView = LayoutInflater.from(this).inflate(R.layout.pw_search_engine, null, false) // 實例化 PopupWindow popupWindow = PopupWindow( pwView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) // 初始化彈窗列表 initRecyclerView() // 設(shè)置 popupWindow popupWindow.isOutsideTouchable = true popupWindow.isTouchable = true popupWindow.isFocusable = true // 加載彈窗動畫 popupWindow.animationStyle = R.style.pw_bottom_anim_style // 設(shè)置彈窗關(guān)閉監(jiān)聽——恢復(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 中存儲的是字符串, // 所以這里先初始化一個資源 id 的數(shù)組,元素類型為整型 val iconResList : MutableList<Int> = mutableListOf() // 通過類型數(shù)組加載相關(guān)引擎資源列表,遍歷其中元素,傳入索引值, // 通過調(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)) } // 記得及時調(diào)用 recycle() 回收 TypedArray 對象 resList.recycle() // 循環(huán),用獲得的 title 和 id 生成對應(yīng)的搜索引擎對象,存入搜索引擎列表中 for (index in titleList.indices){ if (index < iconResList.size){ engines.add(SearchEngine(titleList[index],iconResList[index])) } } }}
到此這篇關(guān)于Android使用 PopupWindow 實現(xiàn)底部彈窗功能的文章就介紹到這了,更多相關(guān)Android PopupWindow底部彈窗內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. Python如何批量生成和調(diào)用變量2. ASP.Net Core對USB攝像頭進(jìn)行截圖3. ASP.NET MVC實現(xiàn)橫向展示購物車4. Python 中如何使用 virtualenv 管理虛擬環(huán)境5. Python獲取B站粉絲數(shù)的示例代碼6. Python基于requests實現(xiàn)模擬上傳文件7. python利用opencv實現(xiàn)顏色檢測8. windows服務(wù)器使用IIS時thinkphp搜索中文無效問題9. ASP.Net Core(C#)創(chuàng)建Web站點的實現(xiàn)10. 通過CSS數(shù)學(xué)函數(shù)實現(xiàn)動畫特效
