干货一:通过自定义PopupWindow实现QQ菜单选项功能
概述
我們在使用手機QQ時,點擊菜單鍵,會彈出如本案例說演示的效果圖似的菜單選項。
實現方式有很多種,在這里我們來演示下如何通過自定義PopupWindow的方式一步一步的實現如上效果。
關于PopupWindow的基本知識點請查看 PopupWindow
分析
UI部分
- shape的使用-corners solid等
- 中間的使用View分割
- 背景的處理
- ……
功能點
- 響應點擊事件–通過接口回調的方式
- 點擊外部,PopupWindow可消失
- ……
實現
自定義PopupWindow
UI編寫
- 位于父布局的底部
- 距邊框有一定的距離,根布局使用layout_margin即可
ListView(四個圓角+白色背景) + View分割(透明色) +底部文字(圓角+白色背景)
藍色字體 居中顯示(ListView中的 在Item設置即可,底部文字設置gravity即可)
- …….
布局文件如下所示:
list_popupwindow.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/id_rl_relativeLayout"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="16dp"android:padding="16dp"><ListView android:id="@+id/id_lv_popupWindowListView"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_above="@+id/view"android:background="@drawable/bg_menu" /><View android:id="@+id/view"android:layout_width="match_parent"android:layout_height="20dp"android:layout_above="@+id/id_tv_bottom"android:background="@color/transparent" /><TextView android:id="@+id/id_tv_bottom"android:layout_width="match_parent"android:layout_height="50dp"android:layout_alignParentBottom="true"android:background="@drawable/bg_menu"android:gravity="center"android:text="取消"android:textColor="@color/skyblue"android:textSize="20dp" /></RelativeLayout>其中用到的幾個背景xml如下,都在drawable目錄下
bg_menu.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><!--stroke: 設置描邊,可描成實線或虛線。當然了也可以不設置stroke屬性--><stroke android:color="@color/transparent"android:width="2dp"/><!--設置形狀填充的顏色,只有android:color一個屬性--><solid android:color="@color/bg_white" /><!-- 設置圓角,只適用于rectangle類型,可分別設置四個角不同半徑的圓角,當設置的圓角半徑很大時,比如200dp,就可變成弧形邊了--><corners android:radius="10dp" /></shape>自定義PopupWindow編寫 +接口回調+監聽OnTouch事件實現點擊外部消失
加載自定義的xml文件,然后獲取ListView組件,設置adapter 即可顯示UI布局。代碼中的注釋已經非常詳細了,再此就不多涉及了。
import android.content.Context; import android.graphics.drawable.ColorDrawable; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; import android.widget.PopupWindow; import android.widget.TextView;import com.turing.base.R; import com.turing.nutritiousSerial.listPopupWindow.adapter.CustomPopupWindowAdpater; import com.turing.nutritiousSerial.listPopupWindow.beans.PopupItemBean;import java.util.List;/*** MyApp** @author Mr.Yang on 2016-04-25 10:12.* @version 1.0* @desc*/ public class ListPopupWindow extends PopupWindow {//上下文private Context context;//父視圖private View parentView;//item數據源private List<PopupItemBean> dataList;//適配器private CustomPopupWindowAdpater adapter;//聲明接口對象private OnPopubItemClickListener popupItemListener;private OnBottomTextViewClickListener bottomTextViewListener;/*** 定義接口用于PopupItem回調點擊事件處理*/public interface OnPopubItemClickListener {void onPopupItemClick(View view, int postion);}/*** 定義接口用于底部TextView回調點擊事件處理*/public interface OnBottomTextViewClickListener {void onBottomClick();}/*** 構造函數*/public ListPopupWindow(Context context,List<PopupItemBean> dataList,View parentView,OnPopubItemClickListener popupItemListener,OnBottomTextViewClickListener bottomTextViewListener) {this.context = context;this.dataList = dataList;this.parentView = parentView;this.popupItemListener = popupItemListener;this.bottomTextViewListener = bottomTextViewListener;initCustomPopupWindow();}/*** 初始化自定義的PopupWindow*/private void initCustomPopupWindow() {// 加載自定義布局文件,轉化為組件parentView = LayoutInflater.from(context).inflate(R.layout.list_popupwindow, null);// 設置顯示的viewsetContentView(parentView);// 初始化控件ListView lv = (ListView) parentView.findViewById(R.id.id_lv_popupWindowListView);TextView tv = (TextView) parentView.findViewById(R.id.id_tv_bottom);// 設置彈出窗體的高this.setWidth(ViewGroup.LayoutParams.MATCH_PARENT);this.setHeight(ViewGroup.LayoutParams.MATCH_PARENT);// 設置彈出窗體可點擊this.setFocusable(true);// 設置SelectPicPopupWindow彈出窗體的背景this.setBackgroundDrawable(new ColorDrawable(0xb0000000));// view添加OnTouchListener監聽判斷獲取觸屏位置如果在布局外面則銷毀彈出框parentView.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// getTop View自身的頂邊到其父布局頂邊的距離,因為是根目錄所以為0int height = parentView.findViewById(R.id.id_rl_relativeLayout).getTop();// getY 點擊事件距離控件頂邊的舉例int y = (int) event.getY();// 當抬起 并且 y>height時(也就是 只要不點擊ListView范圍內),dismiss popupWindowif (event.getAction() == MotionEvent.ACTION_UP) {if (y > height) {dismiss();}}return true;}});// 更新位置和大小(不加這行代碼也行)update();// 實例化適配器adapter = new CustomPopupWindowAdpater(context, dataList);// 設置適配器lv.setAdapter(adapter);// ListView設置點擊事件lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {// 回調onPopupItemClickpopupItemListener.onPopupItemClick(view, position);}});// TextView設置點擊事件tv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 回調onBottomClickbottomTextViewListener.onBottomClick();}});} }CustomPopupWindowAdpater.java
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView;import com.turing.base.R; import com.turing.nutritiousSerial.listPopupWindow.beans.PopupItemBean;import java.util.List;/*** MyApp** @author Mr.Yang on 2016-04-25 11:04.* @version 1.0* @desc*/ public class CustomPopupWindowAdpater extends BaseAdapter {private Context context;private List<PopupItemBean> datas;private LayoutInflater layoutInflater;/*** 構造函數*/public CustomPopupWindowAdpater(Context context, List<PopupItemBean> datas) {this.context = context;this.datas = datas ;layoutInflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return datas.size();}@Overridepublic Object getItem(int position) {return datas.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {// 聲明ViewHolderViewHolder viewHolder;if (convertView == null) {// 加載Item布局,轉換為View布局convertView = layoutInflater.inflate(R.layout.popup_item, parent, false);// 實例化ViewHolderviewHolder = new ViewHolder();// 查找組件賦值給ViewHolderviewHolder.textView = (TextView) convertView.findViewById(R.id.id_tv_popupItemText);// 設置TAGconvertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}// 設置Item中的值viewHolder.textView.setText(datas.get(position).getText() );return convertView;}/*** 對應Item布局中的組件*/class ViewHolder {private TextView textView;} }調用
因為PopupWindow需要依賴父組件來顯示,所以實例話PopupWindow的時候,傳入根布局View,實現接口回調Activity類實現自定義的兩個接口,并傳入到PopupWindow中。
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.Gravity; import android.view.View; import android.widget.RelativeLayout;import com.turing.base.R; import com.turing.base.utils.AlertUtil; import com.turing.nutritiousSerial.listPopupWindow.beans.PopupItemBean; import com.turing.nutritiousSerial.listPopupWindow.customPopupWindow.ListPopupWindow;import java.util.ArrayList; import java.util.List;public class ListPopupWindowDemoActivity extends AppCompatActivity implements ListPopupWindow.OnPopubItemClickListener, ListPopupWindow.OnBottomTextViewClickListener {// 定義父View即PopupWindow依賴浮動的Viewprivate RelativeLayout relativeLayout;private ListPopupWindow popWindow;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_list_popup_window_demo);// 父ViewrelativeLayout = (RelativeLayout) findViewById(R.id.id_rl_relativeLayout);}/*** 按鈕監聽事件** @param view*/public void showCustomListPopupWindow(View view) {// 展示數據集合List<PopupItemBean> datalists = new ArrayList<>();// List集合中的數據PopupItemBean itemBean1 = new PopupItemBean("版本更新");PopupItemBean itemBean2 = new PopupItemBean("反饋");PopupItemBean itemBean3 = new PopupItemBean("退出QQ");// 添加到List集合中datalists.add(itemBean1);datalists.add(itemBean2);datalists.add(itemBean3);// 實例化自定義ListPopupWindowpopWindow = new ListPopupWindow(ListPopupWindowDemoActivity.this,datalists, relativeLayout, this, this);// 居中并且靠底部顯示popWindow.showAtLocation(relativeLayout, Gravity.CENTER | Gravity.BOTTOM, 0, 0);}@Overridepublic void onBottomClick() {popWindow.dismiss();AlertUtil.showToastShort(ListPopupWindowDemoActivity.this, "點擊取消");}@Overridepublic void onPopupItemClick(View view, int postion) {switch (postion) {case 0:AlertUtil.showToastShort(ListPopupWindowDemoActivity.this, String.valueOf(postion) + " 被點擊");break;case 1:AlertUtil.showToastShort(ListPopupWindowDemoActivity.this, String.valueOf(postion) + " 被點擊");break;case 2:AlertUtil.showToastShort(ListPopupWindowDemoActivity.this, String.valueOf(postion) + " 被點擊");break;default:break;}} }代碼已提交Github:
https://github.com/yangshangwei/androidBase/blob/bc0412b47a748177f87d80c9e4bc2e310f2e88c8/androidbase/src/main/java/com/turing/nutritiousSerial/listPopupWindow/test/ListPopupWindowDemoActivity.java
總結
以上是生活随笔為你收集整理的干货一:通过自定义PopupWindow实现QQ菜单选项功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android-Xml绘图
- 下一篇: 干货二:微信SDK-分享初探-更新中