Android中的几种小窗口实现

来源:互联网 发布:淘宝女童模特 编辑:程序博客网 时间:2024/06/10 09:23

在Android经常会碰到各种各样的小窗口,如退出弹窗、菜单弹窗、通知弹窗等等。本文就介绍几种实现小窗口的实例,以后根据情景具体选择实现方法。

惯例,先例出大纲:

  1. Activity式伪弹窗
  2. Dialog式弹窗
  3. Window式弹窗

开始正文~~
1。Activity式伪弹窗

该种情况,其实就是一个Activity,我们只是通过style的作用,把内容部分显示,其他部分都透明化了。
首先,在创建一个Activity和它的布局,这方面不讲了,就一般创建活动流程;
然后,在res/values/styles.xml中添加Activity的具体style,代码及注释如下:

    <style name="MyActivityStyle">        <item name="android:windowBackground">@android:color/transparent</item> <!--设置dialog的背景-->        <item name="android:windowFrame">@null</item> <!--Dialog的windowFrame框为无-->        <item name="android:windowNoTitle">true</item> <!--是否有title-->        <item name="android:windowIsFloating">true</item> <!--是否浮现在activity之上-->        <item name="android:windowIsTranslucent">true</item> <!--是否半透明-->        <item name="android:windowContentOverlay">@null</item> <!--对话框是否有遮盖,这个不设置的话,可能会出现边框黑线-->        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item> <!--动画-->        <item name="android:backgroundDimEnabled">true</item> <!-- 背景是否模糊显示-->    </style>

然后,在AndroidManifest.xml中设置Activity的style:

        <activity            android:name="com.wuxianxi.hunman.smallwindows.MyActivity"            android:theme="@style/MyActivityStyle" >        </activity>

最后,还要在Activity中实现点击事件,如点击空白区退出Activity,很简单:

    @Override    public boolean onTouchEvent(MotionEvent event) {        //点击外围,退出窗口        this.finish();        return true;    }

到此,Activity式伪弹窗已经完成,是不是很简单~~

2。Dialog式弹窗

这里MyDialog的style,使用与上面Activity窗口一样的style, 这部分在此就不多讲了, 下面主要讲MyDialog的自定义过程。
首先,MyDialog的sytle与上面一样,不重复粘贴了。
然后,自定义MyDialog的布局文件xml, 如下:

<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="280dp"    android:layout_height="wrap_content"    android:gravity="center_horizontal"    android:background="@drawable/btn_style_two_normal"    android:orientation="vertical" >    <TextView        android:id="@+id/dialog_title"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginTop="4dp"        android:padding="5dp"        android:textColor="#333"        android:textSize="20sp" />    <TextView        android:id="@+id/dialog_detail"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginTop="1dp"        android:gravity="center_horizontal"        android:padding="10dp"        android:textColor="#333"        android:textSize="16sp" />    <FrameLayout        android:layout_width="match_parent"        android:layout_height="50dp"        android:layout_marginTop="25dp" >        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:background="#EDEDED" >            <TextView                android:id="@+id/dialog_yes"                android:layout_width="0dp"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:text="Yes"                android:textColor="#727272"                android:textSize="16sp" />            <TextView                android:id="@+id/dialog_no"                android:layout_width="0dp"                android:layout_height="match_parent"                android:layout_weight="1"                android:gravity="center"                android:text="No"                android:textColor="#727272"                android:textSize="16sp" />        </LinearLayout>        <View            android:layout_width="match_parent"            android:layout_height="1dp"            android:background="#ccc" />        <View            android:layout_width="1dp"            android:layout_height="match_parent"            android:layout_gravity="center"            android:background="#ccc" />    </FrameLayout></LinearLayout>

然后自定义MyDialog的View类,继承于Dialog类。其中要注意的是实现了点击的回调实现。而MyDialog的style,我直接在里面定义了, 如果想更改style,也可以当参数传进来。代码如下:

package com.wuxianxi.hunman.smallwindows;import android.app.Dialog;import android.content.Context;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.widget.TextView;public class MyDialog extends Dialog implements android.view.View.OnClickListener {    private Context mContext;    private String mTitle;    private String mDetail;    private TextView mTextTitle;    private TextView mTextDetail;    private TextView mButtonYes;    private TextView mButtonNo;    private onClickInterface mOnclClickInterface;    public MyDialog(Context context, String title, String detail) {        super(context, R.style.MyDialogStyle);        this.mContext = context;        this.mTitle = title;        this.mDetail = detail;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        // TODO Auto-generated method stub        super.onCreate(savedInstanceState);        initView();    }    private void initView() {        LayoutInflater inflater = LayoutInflater.from(mContext);        View view = inflater.inflate(R.layout.layout_dialog, null);        setContentView(view);        mButtonYes = (TextView) view.findViewById(R.id.dialog_yes);        mButtonNo = (TextView) view.findViewById(R.id.dialog_no);        mTextTitle = (TextView) view.findViewById(R.id.dialog_title);        mTextDetail = (TextView) view.findViewById(R.id.dialog_detail);        mTextTitle.setText(mTitle);        mTextDetail.setText(mDetail);        mButtonYes.setOnClickListener(this);        mButtonNo.setOnClickListener(this);    }    public interface onClickInterface {        public void clickYes();        public void clickNo();    }    public void setOnClickInterface(onClickInterface onclClickInterface) {        this.mOnclClickInterface = onclClickInterface;    }    @Override    public void onClick(View v) {        switch (v.getId()) {        case R.id.dialog_yes:            mOnclClickInterface.clickYes();            break;        case R.id.dialog_no:            mOnclClickInterface.clickNo();            break;        default:            break;        }    }}

最后当然是在应用中调用MyDialog实例

            //注意下面第一个参数不能为getApplicationContext(),而应该是Activity, 因为办有activity才能添加窗口            final MyDialog dialog = new MyDialog(MainActivity.this, "Hunman - Dialog", "Hunman is a Dialog\nYes or No!");            dialog.show();            dialog.setOnClickInterface(new MyDialog.onClickInterface() {                @Override                public void clickYes() {                    dialog.dismiss();                    Toast.makeText(getApplicationContext(), "Yes, Hunman is Dialog", Toast.LENGTH_LONG).show();                }                @Override                public void clickNo() {                    dialog.dismiss();                    Toast.makeText(getApplicationContext(), "Yes, Hunman is not Dialog", Toast.LENGTH_LONG).show();                }            });

MyDialog的自定义完成,界面不美观,但流程大概是这样~

3。Window式小窗口

使用WindowManager可以显示在其他应用最上层,甚至手机桌面最上层显示窗口。比如电量不足的弹窗。。
这其中有几个知识点要提前了解一下,方便对下面应用实例的理解:
1)WindowManager的了解,这里主要是通过WindowManager.addView()来添加弹出窗口,通过WindowManager.removeView()来关闭弹出的窗口,另外有可能需要用到WindowManager.updateView(), WindowManager主要就这三个函数调用。
具体可能考我之前的一博客:
http://blog.csdn.net/wxx614817/article/details/50500771
2)WindowManager.layoutparams的理解,它是WindowManager 接口的嵌套类;它继承于 ViewGroup.LayoutParams; 它用于向WindowManager描述Window的管理策略。主要是了解LayoutParams 中的各个成员常量的应用情况,如type/flags等。这个网上很多说明文档~

好了, 概念不多说, 直接上代码:
首先, AndroidManifest.xml里添加权限:

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

然后,弹窗的布局:

<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_gravity="center"    android:gravity="center"    android:background="@android:color/transparent"    android:orientation="vertical" >    <LinearLayout        android:id="@+id/view_layout"        android:layout_width="280dp"        android:layout_height="wrap_content"        android:background="@drawable/confirm_dialog_bg2"        android:gravity="center_horizontal"        android:orientation="vertical" >        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="4dp"            android:padding="5dp"            android:text="Hunman - Window"            android:textColor="#333"            android:textSize="20sp" />        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginTop="1dp"            android:gravity="center_horizontal"            android:padding="10dp"            android:text="Human is a Activity\nYes or No?"            android:textColor="#333"            android:textSize="16sp" />        <LinearLayout            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginBottom="8dp"            android:layout_marginTop="33dp" >            <Button                android:id="@+id/window_yes"                android:layout_width="110dp"                android:layout_height="wrap_content"                android:background="@drawable/btn_style_green"                android:gravity="center"                android:onClick="YesButton"                android:text="Yes"                android:textColor="#fff"                android:textSize="16sp" />            <Button                android:id="@+id/window_no"                android:layout_width="110dp"                android:layout_height="wrap_content"                android:layout_marginLeft="10dp"                android:background="@drawable/btn_style_white"                android:gravity="center"                android:onClick="NoButton"                android:text="No"                android:textColor="#333"                android:textSize="16sp" />        </LinearLayout>    </LinearLayout></LinearLayout>

后面当然是弹窗的实现,里面要注意LayoutParams.type常量,如果设置为WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,则像Home/Back键的触发,弹窗监听不到,作用于后面背景应用或桌面,所以弹窗就可以实现一些桌面悬浮按钮的功能。此处不用这个,而用了WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,上代码:

package com.wuxianxi.hunman.smallwindows;import android.content.Context;import android.graphics.PixelFormat;import android.graphics.Rect;import android.util.Log;import android.view.Gravity;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.view.WindowManager.LayoutParams;import android.widget.Button;import android.widget.Toast;public class MyWindow {    private Context mContext;    private WindowManager mwinWindowManager;    private View mView;    private static boolean isShow = false;    public MyWindow(Context context) {        mContext = context.getApplicationContext();    }    public void showMyWindow() {        if (isShow) {            return;        }        mwinWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);        //设置WindowManager.LayoutParams的属性        WindowManager.LayoutParams params = new WindowManager.LayoutParams();        //类型        params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;        //flags        //如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View没焦点,收不到Back键的事件        //当按Back、Home键时,背景应用退出,弹出的view就可以悬浮在桌面了。        params.flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;        params.format = PixelFormat.TRANSLUCENT;        params.width = LayoutParams.MATCH_PARENT;        params.height = LayoutParams.MATCH_PARENT;        params.gravity = Gravity.CENTER;        //初始化View        mView = initView(mContext);        //点击back键,关闭window        mView.setOnKeyListener(new View.OnKeyListener() {            @Override            public boolean onKey(View v, int keyCode, KeyEvent event) {                Log.d("wxx", "onKey");                switch (keyCode) {                case KeyEvent.KEYCODE_BACK:                    Log.d("wxx", "onKey BACK");                    hideMyWindow();                    return true;                default:                return false;                }            }        });        mwinWindowManager.addView(mView, params);        isShow = true;    }    private View initView(Context context) {        LayoutInflater inflater = LayoutInflater.from(context);        View view = inflater.inflate(R.layout.layout_window, null);        Button btnYes = (Button) view.findViewById(R.id.window_yes);        btnYes.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mContext, "Window yes!", Toast.LENGTH_LONG).show();                hideMyWindow();            }        });        Button btnNO = (Button) view.findViewById(R.id.window_no);        btnNO.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Toast.makeText(mContext, "Window No!", Toast.LENGTH_LONG).show();                hideMyWindow();            }        });             //点击window窗口外围,关闭window        final View wView = view.findViewById(R.id.view_layout);        view.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View v, MotionEvent event) {                int x = (int) event.getX();                int y = (int) event.getY();                Rect rect = new Rect();                wView.getGlobalVisibleRect(rect);                if (!rect.contains(x, y)) {                    hideMyWindow();                }                return false;            }        });        return view;    }    public void hideMyWindow() {        if (isShow && mView != null) {            mwinWindowManager.removeView(mView);            isShow = false;        }    }}

这里面有个小缺憾,就是代码里面的OnKeyListener不起作用,发现背景应用也不起作用,不明白为什么,一直没找到原因,那位大神如能给点意见,小弟万分感激。。

到此,三种方式的弹窗都已经完成~~
需要代码的,到我GitHub上面取,链接:
https://github.com/BabyWu/SmallWindows/tree/master/SmallWindows

0 0
原创粉丝点击