您的位置:首页 > 移动开发 > Android开发

Android中的几种小窗口实现

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

惯例,先例出大纲:

Activity式伪弹窗

Dialog式弹窗

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主要就这三个函数调用。

具体可能考我之前的一博客:

/article/10998801.html

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: