PopupWindow的使用原理以及实现卡片效果

来源:互联网 发布:sql语句查询多张表 编辑:程序博客网 时间:2024/05/29 10:54

前记:

  本人菜鸟一枚,第一次写博客,写得不好。不喜勿喷,有疑问的地方可以留言回复~。

 PopupWindow的使用思路:

  在说明他的相关使用方法之前,我们先理清一下它的使用思路。以方便我们针对性的研究各个问题。

  一· 我们大致会使用PopupWindow的场景:

      1.希望点击某些东西之后,能弹出一个独立的操作区域,以承载更多的内容。

      2.满足一些比较不错的设计效果。

     例如下面将提示删除的地方做成一个卡片的形状,并且再赋给它一个动画,那么它会满足material design的设计风格。一个卡片进入界面时从低端滑倒中端进入,退出时从中端滑倒上端退出。

     


  

   二·PopupWindow的使用方法:

       1. PopupWindow的构造方法:

    

     这是PopupWindow的第一个构造方法,传入上下文Context。API中这个构造方法里写的是this(context,null);为什么与会有一个null,那是因为这个构造方法,实质上是调用了

    
      从这个构造方法来看,他还是调用了本类中的其他构造方法。在往后追溯呢,实质上俩个参数的构造方法又调用
了三个参数的构造方法。该方法,我就不传图片了,我直接上API里的代码:
public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {    this(context, attrs, defStyleAttr, 0);}
其实从这个也能看出,它是调用了四个参数的构造方法,最后发现,其实四个参数的构造方法,才是真正的构造
方法:
public PopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {    mContext = context;    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);    final TypedArray a = context.obtainStyledAttributes(            attrs, R.styleable.PopupWindow, defStyleAttr, defStyleRes);    final Drawable bg = a.getDrawable(R.styleable.PopupWindow_popupBackground);    mElevation = a.getDimension(R.styleable.PopupWindow_popupElevation, 0);    mOverlapAnchor = a.getBoolean(R.styleable.PopupWindow_overlapAnchor, false);    // Preserve default behavior from Gingerbread. If the animation is    // undefined or explicitly specifies the Gingerbread animation style,    // use a sentinel value.    if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupAnimationStyle)) {        final int animStyle = a.getResourceId(R.styleable.PopupWindow_popupAnimationStyle, 0);        if (animStyle == R.style.Animation_PopupWindow) {            mAnimationStyle = ANIMATION_STYLE_DEFAULT;        } else {            mAnimationStyle = animStyle;        }    } else {        mAnimationStyle = ANIMATION_STYLE_DEFAULT;    }    final Transition enterTransition = getTransition(a.getResourceId(            R.styleable.PopupWindow_popupEnterTransition, 0));    final Transition exitTransition;    if (a.hasValueOrEmpty(R.styleable.PopupWindow_popupExitTransition)) {        exitTransition = getTransition(a.getResourceId(                R.styleable.PopupWindow_popupExitTransition, 0));    } else {        exitTransition = enterTransition == null ? null : enterTransition.clone();    }    a.recycle();    setEnterTransition(enterTransition);    setExitTransition(exitTransition);    setBackgroundDrawable(bg);}
这个构造方法,我就不一一解释了,因为一些默认属性的设置以及相应初始化方法的步骤。我们会在后面
一点一点的代入进来。

当然PopupWindow
还有一个无参的构造方法,他实质上是调用了三参的构造方法。那么最终也会是调用四参的构造方法:

public PopupWindow() {    this(null, 0, 0);}
    以上是传入Context的构造方法,PopupWindow还有一种传入View的构造方法。后面我们会详细解释这个。
   2.介绍完PopupWindow的构造方法,接下来,我们应该要去了解PopupWindow的组成。
    
    PopupWindow实质上是一个比较特殊的组件,Android中的组件基本上都是继承自View或者ViewGroup。而ViewGroup是继承自View
    那么也就是说,Android中的组件都是继承自View。但是PopupWindow是什么都不继承。所以PopupWindow里面没有什么onDraw方法,也没有什么
onSizeChanged之类的方法让我们可以自定义绘制或者更改组件效果的方法。但是我们可以通过setContentView的方法来设置PopupWindow里的内容
,通过
setBackgroundDrawable
(Drawable background)方法来设置PopupWindow的背景。
   实质上从java的GUI编程中去理解它,
PopupWindow是一个容器。BackgroundDrawable就是容器的形状,而ContentView
就是容器里放的内容。
   三.介绍完PopupWindow的构造方法和它的组成,接下来就是介绍PopupWindow的使用了。
    1.使用PopupWindow,先在创建一个PopupWindow的实例,并且将要放入PopupWindow的内容View实例化。
        
       
//        实例化popupWindow        this.popupWindow = new PopupWindow(mContext);
//        将要放入PopupWindow里的View Inflate出来
         contentview = mInflater.inflate(R.layout.popup_process, null);
      2.接下来就是相应的参数设置了。
通过PopupWindow的setWidth()和setHeight()方法设置PopupWindow的宽高。你可以设置直接的数值,也可以
设置MATCH_PARENT或者WRAP_CONTENT;
//                通过LayoutParams的内质静态变量来设置宽高                popupWindow.setWidth(FrameLayout.LayoutParams.MATCH_PARENT);//                通过自己赋相应的值进去                popupWindow.setHeight((int) TypedValue.applyDimension(                        TypedValue.COMPLEX_UNIT_DIP,                        80,                        mContext.getResources().getDisplayMetrics()));
当然你还需要设置
PopupWindow的contentView,这也是非常重要的。至于设置contentView的宽高,可以通过很多种
方式:
    第一种是在XML文件中设置你inflate进来的布局文件的宽高
    第二种是通过将inflate出来的View的Params属性修改一下
接下来就是设置
PopupWindow的外框背景了,你可以放一个ColorDrawable,或者从res文件中获取一个Drawable文件
                popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
   
     3.接下来是contentView的一些内容:
前面提到的PopupWindow的构造方法中,最后提了一句,
PopupWindow的构造方法中拥有这样一些构造方法:
public PopupWindow(View contentView) {    this(contentView, 0, 0);}
这里我就不要一一赘述了,因为它的构造方法虽然多,但是最后还是调用很多参数的那个构造方法。
    这里我提一下,我们知道
PopupWindow的构造方法中必须含有Context,那么这种构造方法的
Context是从哪里来的呢?
    其实这样的构造方法,Context是来自于contentView里的Context;
    同时我们也可以一步到位创建PopupWindow,就是调用
PopupWindow(View contentView,int width,
int Hegiht);直接将
PopupWindow的内容View和PupupWindow的宽高设置好。
public PopupWindow(View contentView, int width, int height, boolean focusable) {    if (contentView != null) {        mContext = contentView.getContext();        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);    }    setContentView(contentView);    setWidth(width);    setHeight(height);    setFocusable(focusable);}
    4.
PopupWindow里的事件监听:
    前面提到过PopupWindow的使用场景了。我们在使用场景中肯定会去监听一些事件,例如监听Button,EditText
等组件的相应事件。所以这里我们看看
PopupWindow中该如何实现相应的监听
    第一个,我们如果要监听ContentView中的内容,我们必须要设置
       popupWindow.setFocusable(true);
如果不设置这个Focusable为True,那么用户点击contentView上的相应组件,会是无效的。甚至连EditText
的焦点获取都会失效。
    如果我们要监听相应的组件。必须要先将相应的组件实例化出来,一定要通过contentView(你放在PoupWindow
里的View)
去调用findViewById()方法
TextView delete =  (TextView) contentview.findViewById(R.id.popup_delete);TextView back =  (TextView) contentview.findViewById(R.id.popup_back);TextView Content =  (TextView) contentview.findViewById(R.id.popup_content);
接下来就是常规操作了。什么SetOnclickListener,这里就不赘述了
      其次,还有一个叫做
setOutsideTouchable()方法,这个方法的意思是设置除了ContenView以外的区域是否
可以Touch。
    如果说,你想用户点击其他区域时,让PopupWindow消失。必须要这样写才会生效:
popupWindow.setOutsideTouchable(true);contentview.setOnKeyListener(new View.OnKeyListener() {    @Override    public boolean onKey(View v, int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_BACK) {            popupWindow.dismiss();            return true;        }        return false;    }});
    5.PopupWindow的显示位置:
    PopupWindow最大的优势是在于,PopupWindow可以在任意位置显示,这是一个比较易控制的特殊组件。
    它的显示方法有一下几种:
     第一个方法:showAtLocation()的意思,是在指定View的区域显示,第一个参数的意思是被指定的View,
第二个参数的意思是相对于这个View的位置,例如Gravity.CENTER的意思就是PupopWindow相对于View的中间显示
,剩下俩个参数是相对组件Gravity设置基点之后的X,Y偏移量
        剩下的三个方法,可以看出来,基本上类似的。我们从API源码来看区别:
public void showAsDropDown(View anchor) {    showAsDropDown(anchor, 0, 0);}
public void showAsDropDown(View anchor, int xoff, int yoff) {    showAsDropDown(anchor, xoff, yoff, DEFAULT_ANCHORED_GRAVITY);}

public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {    if (isShowing() || mContentView == null) {        return;    }    TransitionManager.endTransitions(mDecorView);    attachToAnchor(anchor, xoff, yoff, gravity);    mIsShowing = true;    mIsDropdown = true;    final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());    preparePopup(p);    final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,            p.width, p.height, gravity);    updateAboveAnchor(aboveAnchor);    p.accessibilityIdOfAnchor = (anchor != null) ? anchor.getAccessibilityViewId() : -1;    invokePopup(p);}

    通过源码API来看,最后一种才是真正的实际上去操作的方法。我们就直接解释最后一个:
    showAsDropDown()方法的意思是,位于某个View的下面显示,第一个是被附着的View,第二个和第三个是X和Y
轴的偏移量。第四个是Gravity,它的意思是相对于被附着的View的位置。
   四.暂时就写这么多了。过些天在写关于实现卡片效果的PopupWindow的博客。第一次写博客,感觉很多东西讲
不完,因为我要把一个东西讲细,要延伸好多其它的知识点= =。感觉自己写的不是很好,有不对的地方或者疑问的
地方,可以直接发邮件给我
   我的邮箱是:1911371025@qq.com
    欢迎邮件我~
原创粉丝点击