Android使用 PopupWindow 實現(xiàn)底部彈窗功能
一、知識點
不詳細展開 PopupWindow 或者視圖動畫的所有具體使用方式,僅僅介紹一下使用的一個大概流程和一些知識要點,具體的介紹在下面設計實現(xiàn)中講述
(一)PopupWindow
1. 初始化
- 加載彈窗的布局
- 實例化 PopupWindow 傳入布局和彈窗的寬高
- 對布局里面的控件的操作
- 對布局本身的一些設置
// 加載彈窗的布局
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()
// 對布局本身的一些設置
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. 關閉彈窗
- 關閉彈窗
- 修改背景亮度—變亮
// 關閉彈窗 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 標簽定義并使用視圖動畫:
1. XML 標簽
- alpha 漸變透明度
- scale 漸變尺寸伸縮
- translate 畫面位置移動
- rotate 畫面轉移旋轉
- set 定義動畫集
2. 給 PopupWindow 添加動畫
popupWindow.animationStyle = R.style.pw_bottom_anim_style
二、界面效果

三、設計實現(xiàn)
(一)需求分析
- 點擊主頁按鈕彈出底部彈窗
- 點擊彈窗引擎,以Toast顯示引擎名稱并關閉彈窗
- 點擊彈窗外部可以關閉彈窗
(二)文件列表

(三)布局設計
1. 主界面樣式設計
(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:id="@+id/btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="14dp" android:text="點擊——底部彈窗" android:textColor="@color/white"/> </LinearLayout>
2. 彈窗樣式設計
(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: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 樣式設計
(item_search_engine.xml)
列表單項,因為是 Demo 示例,所以簡單地用一個橫向布局,內置一個圖標 icon 和一個名稱 TextView 來進行展示
<?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. 彈窗動畫設計
(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 )
以字符串數(shù)組的形式存儲搜索引擎的名稱以及對應的圖標資源
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="search_engine_title_list"> <item>百度</item> <item>搜狗</item> <item>360</item> <item>必應</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ù)組加載相關引擎資源列表,遍歷其中元素,傳入索引值,
// 通過調用 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))
}
// 記得及時調用 recycle() 回收 TypedArray 對象
resList.recycle()
// 循環(huán),用獲得的 title 和 id 生成對應的搜索引擎對象,存入搜索引擎列表中
for (index in titleList.indices){
if (index < iconResList.size){
engines.add(SearchEngine(titleList[index],iconResList[index]))
}
}
}
(五)剩余內容
上述提及的內容代碼,此處將不再進行展示;因為重點是介紹底部彈窗的實現(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ù)進行初始化
mDataList.clear()
mDataList.addAll(dataList)
}
// ViewHolder 方便 item 復用
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()
// 設置 popupWindow
popupWindow.isOutsideTouchable = true
popupWindow.isTouchable = true
popupWindow.isFocusable = true
// 加載彈窗動畫
popupWindow.animationStyle = R.style.pw_bottom_anim_style
// 設置彈窗關閉監(jiān)聽——恢復亮度
popupWindow.setOnDismissListener {
backgroundAlpha(1f)
}
}
private fun showPopWindow() {
val rootView = LayoutInflater.from(this).inflate(
R.layout.activity_main,
null
)
// 設置彈窗位置
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ù)組加載相關引擎資源列表,遍歷其中元素,傳入索引值,
// 通過調用 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))
}
// 記得及時調用 recycle() 回收 TypedArray 對象
resList.recycle()
// 循環(huán),用獲得的 title 和 id 生成對應的搜索引擎對象,存入搜索引擎列表中
for (index in titleList.indices){
if (index < iconResList.size){
engines.add(SearchEngine(titleList[index],iconResList[index]))
}
}
}
}
到此這篇關于Android使用 PopupWindow 實現(xiàn)底部彈窗功能的文章就介紹到這了,更多相關Android PopupWindow底部彈窗內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Android開發(fā)之PopupWindow實現(xiàn)彈窗效果
- Android彈窗ListPopupWindow的簡單應用詳解
- Android PopupWindow實現(xiàn)左側彈窗效果
- Android開發(fā)實現(xiàn)popupWindow彈出窗口自定義布局與位置控制方法
- Android Popupwindow彈出窗口的簡單使用方法
- Android編程實現(xiàn)的自定義彈窗(PopupWindow)功能示例
- Android自定義彈出窗口PopupWindow使用技巧
- Android控件PopupWindow模仿ios底部彈窗
- android PopupWindow 和 Activity彈出窗口實現(xiàn)方式
- Android中PopupWindow彈出式窗口使用方法詳解
相關文章
android初學者必須掌握的Activity狀態(tài)的四大知識點(必讀)
本篇文章主要介紹了android activity的四種狀態(tài),詳細的介紹了四種狀態(tài),包括Running狀態(tài)、Paused狀態(tài)、Stopped狀態(tài)、Killed狀態(tài),有興趣的可以了解一下。2016-11-11
Android仿XListView支持下拉刷新和上劃加載更多的自定義RecyclerView
這篇文章主要介紹了仿XListView支持下拉刷新和上劃加載更多的自定義RecyclerView的實例代碼,非常不錯,具有參考價值,感興趣的朋友可以參考下2016-05-05
Android 啟動 Service(startservice和bindservice) 兩種方式的區(qū)別
andrid service 兩種啟動方式:第一種startservice,第二種bindservice,大家對這兩種啟動方式的區(qū)別了解嗎,下面跟著小編一起學習吧2015-11-11
Android開源項目PullToRefresh下拉刷新功能詳解
這篇文章主要為大家詳細介紹了Android開源項目PullToRefresh下拉刷新功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android?中的?Timer?和?TimerTask詳解
Timer?是?Java?中用于創(chuàng)建定時任務的類,它位于?java.util?包中,可以使用Timer來安排一次性或定期執(zhí)行的任務,這篇文章主要介紹了Android?的?Timer?和?TimerTask,需要的朋友可以參考下2024-05-05

