Android 开发之PopupWindow

本文介绍了一种简化Android应用程序中Dialog及PopupWindow管理的方法,通过创建单例模式的FilterPopupWindow类来统一管理弹出窗口,利用Fragment进行视图切换,提高了代码复用性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个应用程序里面有多个activity和不同的对话框窗体,在我脑海深处的记忆力,对话框的使用一直都是new 出不同的dialog实例然后调用show 、dismiss方法,而弹出视图的控件监听很多时候都是在用CallBack回调函数处理,并且弹出视图获取控件基本都是(xxx)converView.findbyid..我开始发现我做的每个项目都这么写类似代码,于是乎开始了我的思考:一个应用只new一个dialog或者PopupWindow实例?不同的dialog显示可以不可以用类似FragmentManage管理?弹出视图的控件获取能不能更简单一点?于是乎一个简单的demo原型就出来了。

这是一个简单的筛选demo,模拟数据类MenuData.java是由android studio插件GsonFormat生成,对生成的set get进行了简单的修改,这里就不贴详细代码了,下面是生成代码类和GsonFormat使用的效果图。


import java.util.List;

/**
 * Created by LanYan on 2015/8/27.
 */
public class MenuData {

    /**
     * sortLIst : [{"count":"2345","sortId":"2004748","sortType":"1","sortName":"预付卡商户"},{"count":"2345","sortId":"2004748","sortType":"1","sortName":"预付卡商户"},{"count":"2345","sortId":"2004748","sortType":"1","sortName":"预付卡商户"}]
     * cityId : 30000534
     * checkAreaId : 23423423
     * cityName : 成都
     * checkSmartId : 234242342
     * checkSortName : 预付卡商户
     * checkSortId : 2342e544
     * checkSmartName : 天天折扣
     * checkAreaName :
     * checkTypeName : 美食
     * searchName :
     * smartList : [{"smartName":"天天半价","smartId":"2004748"},{"smartName":"天天折扣","smartId":"2004748"},{"smartName":"预付卡商户","smartId":"2004748"}]
     * areaList : [{"parentId":"10003","count":"32453","childList":[{"childId":"1000031","childName":"盐市口"},{"childId":"1000032","childName":"春熙路"}],"parentName":"锦江"},{"parentId":"10003","count":"32453","childList":[{"childId":"1000031","childName":"盐市口"},{"childId":"1000032","childName":"春熙路"}],"parentName":"锦江"}]
     * checkTypeId : 234234
     * typeList : [{"parentId":"10003","count":"32453","childList":[{"childId":"1000031","childName":"盐市口"},{"childId":"1000032","childName":"春熙路"}],"parentName":"锦江"},{"parentId":"10003","count":"32453","childList":[{"childId":"1000031","childName":"盐市口"},{"childId":"1000032","childName":"春熙路"}],"parentName":"锦江"}]
     */
    private List<SortLIstEntity> sortLIst;
    private String cityId;
    private String checkAreaId;
    private String cityName;
    private String checkSmartId;
    private String checkSortName;
    private String checkSortId;
    private String checkSmartName;
    private String checkAreaName;
    private String checkTypeName;
    private String searchName;
    private List<SmartListEntity> smartList;
    private List<AreaListEntity> areaList;
    private String checkTypeId;
    private List<TypeListEntity> typeList;

     .........................此处省略.................................
    @Override
    public String toString() {
        return "MenuData [sortLIst=" + sortLIst + ", cityId=" + cityId
                + ", checkAreaId=" + checkAreaId + ", cityName=" + cityName
                + ", checkSmartId=" + checkSmartId + ", checkSortName="
                + checkSortName + ", checkSortId=" + checkSortId
                + ", checkSmartName=" + checkSmartName + ", checkAreaName="
                + checkAreaName + ", checkTypeName=" + checkTypeName
                + ", searchName=" + searchName + ", smartList=" + smartList
                + ", areaList=" + areaList + ", checkTypeId=" + checkTypeId
                + ", typeList=" + typeList + "]";
    }

}

下面是一个FilterPopupWindow 对PopupWindow类操作的封装:


public class FilterPopupWindow {

    private static FilterPopupWindow mFilterPopupWindow;
    private PopupWindow mPopupWindow;


    public PopupWindow getmPopupWindow() {
        return mPopupWindow;
    }
    public void setmPopupWindow(PopupWindow mPopupWindow) {
        this.mPopupWindow = mPopupWindow;
    }
    private FilterPopupWindow(){

    }
    public static FilterPopupWindow getInstance(){
        if(mFilterPopupWindow==null){
            synchronized (FilterPopupWindow.class) {

                if(mFilterPopupWindow==null){
                    mFilterPopupWindow=new FilterPopupWindow();
                }
            }
        }
        return mFilterPopupWindow;
    }

    public PopupWindow onCreatePopupWindow(Activity mActivity,View view){

        WindowManager manager=(WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics=new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(outMetrics);
        int mWidth=outMetrics.widthPixels;
        int mHeight=outMetrics.heightPixels;
        mPopupWindow=new PopupWindow(mActivity);
        mPopupWindow.setWidth(mWidth);
        mPopupWindow.setHeight(mHeight);
        mPopupWindow.setContentView(view);
        mPopupWindow.setAnimationStyle(R.style.FilterPopupWindow);
        mPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#00000000")));
        mPopupWindow.setFocusable(false);
        mPopupWindow.setOutsideTouchable(false);
        mPopupWindow.update();      
        return mPopupWindow;
    }

    public void showPopupWindow(Activity mActivity,int position,View anchor,OnPopupWindowListener mOnPopupWindowListener){

        if(mPopupWindow==null){
            View mView=FilterView.getInstance().getDecorView(mActivity,position,mOnPopupWindowListener);
            mPopupWindow=FilterPopupWindow.getInstance().onCreatePopupWindow(mActivity,mView);
        }

        if(mPopupWindow!=null&&!mPopupWindow.isShowing()){
            FilterView.getInstance().setFragmentWithPosition(position);
            mPopupWindow.showAsDropDown(anchor);
        }else if(mPopupWindow!=null&&mPopupWindow.isShowing()){
            FilterView.getInstance().setFragmentWithPosition(position);
        }
    }

    public void dismissPopupWindow(Activity mActivity){
        if(mPopupWindow!=null&&mPopupWindow.isShowing()){
            mPopupWindow.dismiss();
        }
    }

    public boolean isShowing(){
        if(mPopupWindow!=null){
            return mPopupWindow.isShowing();
        }else{
            return false;
        }
    }
}

下面是一个不太理想的Fragment的管理模式却是我需要的模式FilterView.java,通过setFragmentWithPosition控制Fragment的显示和隐藏,FramLayout静态加载Fragment,在不同场景加载不同弹出视图,用FragmentManage管理,通过replace方法替换最好。


import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import com.lanyan.data.DataHelper;
import com.lanyan.filter.R;
import com.lanyan.interfaces.OnPopupWindowListener;
import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.view.annotation.ViewInject;
@SuppressLint({ "InflateParams", "ClickableViewAccessibility" })

public class FilterView {
    private static FilterView mFilterView;
    private View mView;
    ArrayList<BasicFilterFragment> mListFragments=new ArrayList<BasicFilterFragment>();

    @ViewInject(R.id.filter_cancel)
    private View mCancel;

    @ViewInject(R.id.framgent_parent_filter)
    private FrameLayout mFramLayout;
    private FilterView(){

    }
    public static FilterView getInstance() {

        if (mFilterView == null) {
            synchronized (DataHelper.class) {
                if (mFilterView == null) {
                    mFilterView = new FilterView();
                }
            }
        }
        return mFilterView;
    }
    public View getDecorView(final Activity mActivity,final int position,
            final OnPopupWindowListener mOnPopupWindowListener) {
        if(mView==null){
            mView=mActivity.getLayoutInflater().inflate(R.layout.fragment_filter, null);
            ViewUtils.inject(this,mView);
            mCancel.setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    mOnPopupWindowListener.onCancel();
                    return false;
                }
            });
        }
        return mView;
    }
    public void setFragmentWithPosition(int position){
        for (int i = 0; i < 4; i++) {
            if(i==position){
                mFramLayout.getChildAt(i).setVisibility(View.VISIBLE);
            }else{
                mFramLayout.getChildAt(i).setVisibility(View.INVISIBLE);
            }
        }
    }
}

当Fragment加载Dialog视图后控件的引用可以更简单的想Activity一样获取控件,这里采用的是xutils第三方开源项目的注解模块的功能。


import java.util.ArrayList;
import java.util.List;

import android.widget.ListView;

import com.lanyan.adapter.AreaChildAdapter;
import com.lanyan.adapter.AreaParentAdapter;
import com.lanyan.adapter.ListAdapter.OnItemCheckListener;
import com.lanyan.data.MenuData;
import com.lanyan.data.MenuData.AreaListEntity;
import com.lanyan.data.MenuData.AreaListEntity.ChildListEntity;
import com.lanyan.filter.R;
import com.lidroid.xutils.view.annotation.ViewInject;


public class AreaFragment extends BasicFilterFragment{

    @ViewInject(R.id.parentListView)
    ListView mParentListView;

    @ViewInject(R.id.childListView)
    ListView mChildListView;
    List<AreaListEntity> mList=new ArrayList<MenuData.AreaListEntity>();

    private AreaParentAdapter parentAdapter;

    private AreaChildAdapter childAdapter;
    @Override
    public int getCurrentView() {
        // TODO Auto-generated method stub
        return R.layout.filter_area;
    }

    @Override
    protected void initView() {
        // TODO Auto-generated method stub
        super.initView();
        mList=mActivity.mMenuData.getAreaList();
        if(mList.size()>0&&mList.get(0).getChildList().size()>0){
            initialized();
        }
    }

    private void initialized() {
    }
    .....................此处省略........................
    }

以前我们dialog的回调监听通过接口实现,那么现在这个同样可以,不过这里使用的原理相同,不过是直接通过activity调引用方法块。实例如下:

childAdapter.setOnItemCheckListener(new  OnItemCheckListener<MenuData.AreaListEntity.ChildListEntity>() {

            @Override
            public void onChecked(ChildListEntity result) {
                mActivity.onCancel();
                mActivity.onAreaChanged(result);
            }
        });

这里的mActivity来自于Fragment基类的getActivity类型强转,这个转换只适合该demo,不同的activity应该强转不同的类型这个操作需要放到自身Fragment里面。 这里的链级列表筛选的适配器继承自超级基类ListAdapter,该类是对BaseAdapter进行了简单的继承封装。


import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
 *
 * @param <T>
 */
public abstract class ListAdapter<T> extends BaseAdapter {

    public LayoutInflater inflater=null;
    protected List<T> list;
    protected Activity context;


    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        if(list==null){
            list=new ArrayList<T>();
        }
        this.list = list;
    }

    /***
     * 刷新
     * @param newList
     */
    public void onRefersh(List<T> newList){
        if(newList!=null&&newList.size()>0){
            this.setList(newList);
            this.notifyDataSetChanged();
        }else{
            list=new ArrayList<T>();
            this.notifyDataSetChanged();
        }
    }
    /***
     * 加载跟多
     * @param newList
     */
    public void onLoadMore(List<T> newList){
        if(newList!=null&&newList.size()>0){
            for (int i = 0; i < newList.size(); i++) {
                list.add(newList.get(i));
            }
            this.notifyDataSetChanged();
        }
    }


    /**
     * 移除某一项
     * @param t
     */
    public void removeItem(T t){
        if(t!=null){
            list.remove(t);
            this.notifyDataSetChanged();
        }
    }
    /**
     * 移除多项
     * @param t
     */
    public void removeListItem(List<T> newList){
        if(newList!=null&&newList.size()>0){
            for(T t:newList){
                if(list.contains(t)){
                    list.remove(t);
                }
            }
            this.notifyDataSetChanged();
        }
    }
    public ListAdapter(Activity mcontext,List<T> list){
        this.context=mcontext;
        this.inflater=LayoutInflater.from(context);
        this.setList(list);
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return list.size();
    }

    @Override
    public T getItem(int position) {
        // TODO Auto-generated method stub
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        int layout=setContentView();
        if(convertView==null){
            convertView=inflater.inflate(layout, null);
        }
        initialized(convertView,getItem(position),onItemCheckListener);
        return convertView;
    }
    public abstract int setContentView();
    public abstract void initialized(View view,T result,OnItemCheckListener<T> listener);

    public interface OnItemCheckListener<T>{
        void onChecked(T result);
    }
    private OnItemCheckListener<T> onItemCheckListener;


    public OnItemCheckListener<T> getOnItemCheckListener() {
        return onItemCheckListener;
    }

    public void setOnItemCheckListener(OnItemCheckListener<T> onItemCheckListener) {
        this.onItemCheckListener = onItemCheckListener;
    }

}

从此Adapter的使用就简单化了配合ViewHolder使用实例如下


import java.util.List;

import android.app.Activity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;

import com.lanyan.data.MenuData.AreaListEntity;
import com.lanyan.data.MenuData.AreaListEntity.ChildListEntity;
import com.lanyan.filter.R;

public class AreaChildAdapter extends ListAdapter<AreaListEntity.ChildListEntity> {

    public AreaChildAdapter(Activity mcontext, List<ChildListEntity> list) {
        super(mcontext, list);
        // TODO Auto-generated constructor stub
    }

    @Override
    public int setContentView() {
        // TODO Auto-generated method stub
        return R.layout.popupwindow_area_child;
    }

    @Override
    public void initialized(
            View view,
            final ChildListEntity result,
            final com.lanyan.adapter.ListAdapter.OnItemCheckListener<ChildListEntity> listener) {
        // TODO Auto-generated method stub
        ViewHolder.setTextView(view, R.id.child, result.getChildName());
        LinearLayout mLayout=ViewHolder.get(view, R.id.parent_layout);
        mLayout.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if(listener!=null){
                listener.onChecked(result); 
                }
            }
        });
    }

}

流式布局和ListView的适配器参考资料来自鸿洋的博客:http://blog.youkuaiyun.com/lmj623565791?viewmode=contents,下面是demo相关源码链级:http://download.youkuaiyun.com/detail/analyzesystem/9069827

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值