整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

干货:HTML JS中你不一定知道的alert!

avaweb

经常做微信或者手机网页开发的小伙伴们一定有这样的苦恼,我们经常要在HTML 或者jsp 中输出一些日志来确认获取到的数据是不是我们想要的,或者利用输出的日志来进行排错,

不像chrome那样,有功能强大的dev tools来调试代码,因为在手机端我们无法看到console.log这样的日志。

那么我们通常会alert一下,但是我们alert一个字符串啊什么的还行,alert一个对象的话就不行了,会弹出一个[object Object] 如下图:

Javaweb

那么我今天就来教大家怎么样alert出对象的信息:

Javaweb

方法就是: alert(JSON.stringify(obj, null, 4));//(其中的obj,就是你的js对象)

是不是很方便,很神奇了?

我在后续的文章中,会分享更多更实用的开发小技巧给大家,希望大家多多关注!

  • 现在很多App里都内置了Web网页(Hybrid App),比如说很多电商平台,淘宝、京东、聚划算等等,如下图

  • 上述功能是由Android的WebView实现的,其中涉及到Android客户端与Web网页交互的实现
  • 今天我将全面介绍Android通过WebView与JS交互的全面方式

阅读本文前请先阅读:Android开发:最全面、最易懂的Webview详解


目录


1. 交互方式总结

Android与JS通过WebView互相调用方法,实际上是:

  • Android去调用JS的代码
  • JS去调用Android的代码

二者沟通的桥梁是WebView

对于Android调用JS代码的方法有2种:

1. 通过WebView的loadUrl()

2. 通过WebView的evaluateJavascript()

对于JS调用Android代码的方法有3种:

1. 通过WebView的addJavascriptInterface()进行对象映射

2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url

3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息


2. 具体分析

2.1 Android通过WebView调用 JS 代码

对于Android调用JS代码的方法有2种:

1. 通过WebView的loadUrl()

2. 通过WebView的evaluateJavascript()

方式1:通过WebView的loadUrl()

  • 实例介绍:点击Android按钮,即调用WebView JS(文本名为javascript)中callJS()
  • 具体使用:

步骤1:将需要调用的JS代码以.html格式放到src/main/assets文件夹里

  • 为了方便展示,本文是采用Andorid调用本地JS代码说明;
  • 实际情况时,Android更多的是调用远程JS代码,即将加载的JS代码路径改成url即可

需要加载JS代码:javascript.html

// 文本名:javascript

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>Carson_Ho</title>

// JS代码

<script>

// Android需要调用的方法

function callJS(){

alert("Android调用了JS的callJS方法");

}

</script>

</head>

</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

步骤2:在Android里通过WebView设置调用JS代码

Android代码:MainActivity.java

注释已经非常清楚

public class MainActivity extends AppCompatActivity {

WebView mWebView;

Button button;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mWebView =(WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

// 设置与Js交互的权限

webSettings.setJavaScriptEnabled(true);

// 设置允许JS弹窗

webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

// 先载入JS代码

// 格式规定为:file:///android_asset/文件名.html

mWebView.loadUrl("file:///android_asset/javascript.html");

button = (Button) findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

// 通过Handler发送消息

mWebView.post(new Runnable() {

@Override

public void run() {

// 注意调用的JS方法名要对应上

// 调用javascript的callJS()方法

mWebView.loadUrl("javascript:callJS()");

}

});

}

});

// 由于设置了弹窗检验调用结果,所以需要支持js对话框

// webview只是载体,内容的渲染需要使用webviewChromClient类去实现

// 通过设置WebChromeClient对象处理JavaScript的对话框

//设置响应js 的Alert()函数

mWebView.setWebChromeClient(new WebChromeClient() {

@Override

public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {

AlertDialog.Builder b = new AlertDialog.Builder(MainActivity.this);

b.setTitle("Alert");

b.setMessage(message);

b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

result.confirm();

}

});

b.setCancelable(false);

b.create().show();

return true;

}

});

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

特别注意:JS代码调用一定要在 onPageFinished() 回调之后才能调用,否则不会调用。

onPageFinished()属于WebViewClient类的方法,主要在页面加载结束时调用

方式2:通过WebView的evaluateJavascript()

  • 优点:该方法比第一种方法效率更高、使用更简洁。
  • 因为该方法的执行不会使页面刷新,而第一种方法(loadUrl )的执行则会。
  • Android 4.4 后才可使用
  • 具体使用

// 只需要将第一种方法的loadUrl()换成下面该方法即可

mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {

@Override

public void onReceiveValue(String value) {

//此处为 js 返回的结果

}

});

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2.1.2 方法对比

2.1.3 使用建议

两种方法混合使用,即Android 4.4以下使用方法1,Android 4.4以上方法2

// Android版本变量

final int version = Build.VERSION.SDK_INT;

// 因为该方法在 Android 4.4 版本才可使用,所以使用时需进行版本判断

if (version < 18) {

mWebView.loadUrl("javascript:callJS()");

} else {

mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {

@Override

public void onReceiveValue(String value) {

//此处为 js 返回的结果

}

});

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

2.2 JS通过WebView调用 Android 代码

对于JS调用Android代码的方法有3种:

1. 通过WebView的addJavascriptInterface()进行对象映射

2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url

3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

2.2.1 方法分析

方式1:通过 WebView的addJavascriptInterface()进行对象映射

步骤1:定义一个与JS对象映射关系的Android类:AndroidtoJs

AndroidtoJs.java(注释已经非常清楚)

// 继承自Object类

public class AndroidtoJs extends Object {

// 定义JS需要调用的方法

// 被JS调用的方法必须加入@JavascriptInterface注解

@JavascriptInterface

public void hello(String msg) {

System.out.println("JS调用了Android的hello方法");

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

步骤2:将需要调用的JS代码以.html格式放到src/main/assets文件夹里

需要加载JS代码:javascript.html

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>Carson</title>

<script>

function callAndroid(){

// 由于对象映射,所以调用test对象等于调用Android映射的对象

test.hello("js调用了android中的hello方法");

}

</script>

</head>

<body>

//点击按钮则调用callAndroid函数

<button type="button" id="button1" onclick="callAndroid()"></button>

</body>

</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

步骤3:在Android里通过WebView设置Android类与JS代码的映射

详细请看注释

public class MainActivity extends AppCompatActivity {

WebView mWebView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

// 设置与Js交互的权限

webSettings.setJavaScriptEnabled(true);

// 通过addJavascriptInterface()将Java对象映射到JS对象

//参数1:Javascript对象名

//参数2:Java对象名

mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS类对象映射到js的test对象

// 加载JS代码

// 格式规定为:file:///android_asset/文件名.html

mWebView.loadUrl("file:///android_asset/javascript.html");

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

特点

  • 优点:使用简单

仅将Android对象和JS对象映射即可

  • 缺点:存在严重的漏洞问题,具体请看文章:你不知道的 Android WebView 使用漏洞

方式2:通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url

  • 具体原理:
  1. Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
  2. 解析该 url 的协议
  3. 如果检测到是预先约定好的协议,就调用相应方法

即JS需要调用Android的方法

  • 具体使用:
  • 步骤1:在JS约定所需要的Url协议
  • JS代码:javascript.html

以.html格式放到src/main/assets文件夹里

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>Carson_Ho</title>

<script>

function callAndroid(){

/*约定的url协议为:js://webview?arg1=111&arg2=222*/

document.location = "js://webview?arg1=111&arg2=222";

}

</script>

</head>

<!-- 点击按钮则调用callAndroid()方法 -->

<body>

<button type="button" id="button1" onclick="callAndroid()">点击调用Android代码</button>

</body>

</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

当该JS通过Android的mWebView.loadUrl("file:///android_asset/javascript.html")加载后,就会回调shouldOverrideUrlLoading (),接下来继续看步骤2:

步骤2:在Android通过WebViewClient复写shouldOverrideUrlLoading ()

MainActivity.java

public class MainActivity extends AppCompatActivity {

WebView mWebView;

// Button button;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

// 设置与Js交互的权限

webSettings.setJavaScriptEnabled(true);

// 设置允许JS弹窗

webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

// 步骤1:加载JS代码

// 格式规定为:file:///android_asset/文件名.html

mWebView.loadUrl("file:///android_asset/javascript.html");

// 复写WebViewClient类的shouldOverrideUrlLoading方法

mWebView.setWebViewClient(new WebViewClient() {

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

// 步骤2:根据协议的参数,判断是否是所需要的url

// 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)

//假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

Uri uri = Uri.parse(url);

// 如果url的协议 = 预先约定的 js 协议

// 就解析往下解析参数

if ( uri.getScheme().equals("js")) {

// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议

// 所以拦截url,下面JS开始调用Android需要的方法

if (uri.getAuthority().equals("webview")) {

// 步骤3:

// 执行JS所需要调用的逻辑

System.out.println("js调用了Android的方法");

// 可以在协议上带有参数并传递到Android上

HashMap<String, String> params = new HashMap<>();

Set<String> collection = uri.getQueryParameterNames();

}

return true;

}

return super.shouldOverrideUrlLoading(view, url);

}

}

);

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

特点

  • 优点:不存在方式1的漏洞;
  • 缺点:JS获取Android方法的返回值复杂。

如果JS想要得到Android方法的返回值,只能通过 WebView 的 loadUrl ()去执行 JS 方法把返回值传递回去,相关的代码如下:

// Android:MainActivity.java

mWebView.loadUrl("javascript:returnResult(" + result + ")");

// JS:javascript.html

function returnResult(result){

alert("result is" + result);

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

方式3:通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息

在JS中,有三个常用的对话框方法:

方式3的原理:Android通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调分别拦截JS对话框

(即上述三个方法),得到他们的消息内容,然后解析即可。

下面的例子将用拦截 JS的输入框(即prompt()方法)说明 :

  • 常用的拦截是:拦截 JS的输入框(即prompt()方法)
  • 因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值

步骤1:加载JS代码,如下:

javascript.html

以.html格式放到src/main/assets文件夹里

<!DOCTYPE html>

<html>

<head>

<meta charset="utf-8">

<title>Carson_Ho</title>

<script>

function clickprompt(){

// 调用prompt()

var result=prompt("js://demo?arg1=111&arg2=222");

alert("demo " + result);

}

</script>

</head>

<!-- 点击按钮则调用clickprompt() -->

<body>

<button type="button" id="button1" onclick="clickprompt()">点击调用Android代码</button>

</body>

</html>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

当使用mWebView.loadUrl("file:///android_asset/javascript.html")加载了上述JS代码后,就会触发回调onJsPrompt(),具体如下:

  • 如果是拦截警告框(即alert()),则触发回调onJsAlert();
  • 如果是拦截确认框(即confirm()),则触发回调onJsConfirm();

步骤2:在Android通过WebChromeClient复写onJsPrompt()

public class MainActivity extends AppCompatActivity {

WebView mWebView;

// Button button;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();

// 设置与Js交互的权限

webSettings.setJavaScriptEnabled(true);

// 设置允许JS弹窗

webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

// 先加载JS代码

// 格式规定为:file:///android_asset/文件名.html

mWebView.loadUrl("file:///android_asset/javascript.html");

mWebView.setWebChromeClient(new WebChromeClient() {

// 拦截输入框(原理同方式2)

// 参数message:代表promt()的内容(不是url)

// 参数result:代表输入框的返回值

@Override

public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {

// 根据协议的参数,判断是否是所需要的url(原理同方式2)

// 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)

//假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

Uri uri = Uri.parse(message);

// 如果url的协议 = 预先约定的 js 协议

// 就解析往下解析参数

if ( uri.getScheme().equals("js")) {

// 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议

// 所以拦截url,下面JS开始调用Android需要的方法

if (uri.getAuthority().equals("webview")) {

//

// 执行JS所需要调用的逻辑

System.out.println("js调用了Android的方法");

// 可以在协议上带有参数并传递到Android上

HashMap<String, String> params = new HashMap<>();

Set<String> collection = uri.getQueryParameterNames();

//参数result:代表消息框的返回值(输入值)

result.confirm("js调用了Android的方法成功啦");

}

return true;

}

return super.onJsPrompt(view, url, message, defaultValue, result);

}

// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述

// 拦截JS的警告框

@Override

public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

return super.onJsAlert(view, url, message, result);

}

// 拦截JS的确认框

@Override

public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {

return super.onJsConfirm(view, url, message, result);

}

}

);

}

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

  • Demo地址
  • 上述所有代码均存放在:Carson_Ho的Github地址 : WebView Demo

2.2.2 三种方式的对比 & 使用场景


3. 总结

  • 本文主要对Android通过WebView与JS的交互方式进行了全面介绍

  • 关于WebView的系列文章对你有所帮助
  • Android开发:最全面、最易懂的Webview详解
  • Android:你不知道的 WebView 使用漏洞
  • 手把手教你构建 Android WebView 的缓存机制 & 资源预加载方案
  • 接下来我会继续讲解其他安卓开发的知识,有兴趣可以继续关注Carson_Ho的安卓开发笔记!!!!

请评论点赞!因为你们的赞同/鼓励是我写作的最大动力!

窗的类型有非常多种,所以在使用时很容易被滥用,这样不仅会对用户带来困扰,也会让我们的设计中出现细枝末节的问题。本篇文章分析和总结了不同弹窗的使用场景及工作中的实际应用,知道这些后,以后再也不会“滥用”弹窗啦!

一、前言

我们口中常说的弹窗其实是个广义的范围,包括了对话框,动作菜单,浮出层,toast,snackbar等,这么多类型的弹窗在使用中很容易混乱或者说滥用,反而得不偿失,给用户带来更多困扰。故本篇文章主要分析和总结不同弹窗的使用场景及工作中的实际应用。

官方的设计样式会提到,但是细节不展开,有需要的可以参阅MD官方文档和苹果HIG官方文档,文档里介绍的都很细致。

除了官方文档,本文还参阅了很多前辈的总结分析,参考链接已置于文末。(配图主要来自体验过程中的app截图,安卓部分截图主要来自MD规范)

二、什么是弹窗

在App使用中,弹窗出现的频率越来越高,运营活动,系统通知,信息反馈,任务引导等。滥用的弹窗会渐渐导致用户认知疲劳和视觉失调,甚至会出现“习惯性取消”等行为。

弹窗最主要的功能就是服务于当前主任务之外的支线任务,包括信息传递,操作反馈等。

对话框,警告框,toast……都属于弹窗,但是使用场景都不一样。

在合适的业务场景选择合适的弹窗组件,能够保证最基础的用户体验。因为像强干扰类弹窗的使用,对用户而言,更是一种强加的任务,很容易导致用户丧失耐心而流失。

三、弹窗有哪些

弹窗可以按照是否强制打断用户操作来分成两种,模态弹窗和非模态弹窗(也可以叫做阻断式弹窗和非阻断式弹窗)。

3.1 模态弹窗

模态弹窗:模态提供了一个专注聚焦的环境,用户只有完成或者关闭当前任务,才能进行其他任务。

特点:打断用户当前的操作流程,属于强势的干扰行为,故运用弹窗需要慎重考虑。

常用组件:dialog(对话框)/alert(警告框)、popover(浮出层)、action sheet(动作菜单)、activity views(活动视图)、modal bottom sheet(模态底部菜单)。

3.2 非模态弹窗

非模态弹窗:常用于轻量级的操作反馈和信息传递,不需要获取屏幕焦点,用户可以同时操作屏幕中的其他内容。

特点:属于轻量级的反馈,不会对用户流程产生干扰,但同时又给了用户反馈和信息。

常用组件:Toast(吐司),snackbar,Hud(透明指示层)。

四.具体使用

4.1 强干扰类——dialog(对话框)/alert(警告框)

dialog和alert分别是MD和ios的官方弹出框,是最常见的弹窗,两者功能一样,在使用上以及样式上略有区别(下文分析统一称为弹出框)。

弹出框通常用来传达和app及设备相关的重要信息,并且要求用户操作或反馈,且其出现在屏幕中央,对内容遮挡严重,会中断用户正常操作。用户只有完成或者关闭当前任务,才能进行其他任务。

其官方样式如下:

4.1.1 使用场景

通知用户app或设备相关的问题:

通过强干扰通知用户设备相关问题如备份,低电量等问题;这些潜在问题可能会对用户造成一定负面的影响。

再比如app的版本更新,消息通知,首饰引导等都关系到用户的利益,所以也会用强干扰的方式让用户明确知道并选择。

辅助用户完成任务,如系统权限:

用户在进行任务的过程中,受到阻拦,必须通过其他辅助操作帮助他完成任务。

如完成一些任务必须要开启相应的系统权限:上传照片要开启相册权限;拍小视频要麦克风权限;出行外卖等产品要开启定位权限;新建相册必须要为相册命名;下载app要登录itunes账号。

用户主动中断任务,破坏性操作等:

用户中断当前任务,对之前的操作有一定的影响,或者一些无法挽回的破坏性操作,故需强干扰的弹窗通知,避免用户因为失误有了不可挽回的损失。如退出账号;删除订单,活动消息等;放弃编辑。

操作反馈:

当操作后的反馈比较重要,会影响用户接下来的操作或会影响当下的任务,那就需要用强干扰让用户明确知道,要完成此操作需要什么,或者接下来会发生什么。

例如西瓜视频的结算通过强干扰通知到用户想要结算应该怎么做。

运营活动:

现在用弹出框来传递运营活动已经成为一个约定俗成的用法了,虽然ios规范中建议尽量少用弹出框,但公司还是要盈利的,所以基本上所有app都会以这种强干扰的形式来通知用户“这里有优惠活动”等运营活动。

这种场景下,弹出框会根据产品以及业务的运营需求及产品的调性做丰富的运营设计,来吸引用户参加运营活动,需要注意的一点,需要用户参加的buttom一定要加强,突出。

功能引导:

功能引导和运营活动一样,是产品出于业务角度考虑,用强干扰的方式吸引用户使用某功能,达到一定的业务目标,如用户活跃度。

例如完成订单后(外卖或商品)引导用户评价,并给予一定奖励。如将流量引流到新业务,从而达到新业务推广目的。

4.2 强干扰——popover(浮出层)

浮出层是ios的组件,是用户点击屏幕上的某个控件或区域出现在屏幕上方的临时视图,它最典型的是包含一个指向它出现位置的箭头,且浮出层一般在入口下方,整个浮出层应该位于整个屏幕的中上方。

浮出层最开始主要用于大屏幕的ipad,但由于手机屏幕越来越大,目前也被较多地运用到手机界面中。

4.2.1 使用场景

多个常用操作的快捷入口:

多个常用操作通过popover折叠起来,视觉上更清爽简洁,同时使用起来也方便,缺点是用户不能直观看到,需要一定的学习才能掌握,所以适合于有学习能力用户群的产品

呈现页面中一些折叠的信息:

属于浮出层的衍生应用,和上个场景一样,节约屏幕空间,显露出一部分,并将剩余信息折叠起来,不影响用户理解功能,又解决了屏幕空间,若用户有需求,即可展开探索更多的信息,同样也会用箭头等指向出处

对于新用户的功能引导或者新功能的引导:

此类场景也属于浮出层的衍生应用,主要通过带指向箭头的浮层引导用户学习某个功能,一般需要学习的功能是高亮的,且箭头指向它。

4.3 强干扰——action sheet(动作菜单)

actionsheet是ios系统中特定的警告框,用来响应动作或控件,或者呈现和当前内容相关的两个及更多的选项。一般在屏幕底部。官方不建议在动作菜单中应用滚动条,所以动作菜单中的选项不能过多。

4.3.1 使用场景

当前对象的多个操作或者完成任务的多个选择:

对当前对象的的多个操作,如qq中对图片长按,出现多个对该图片可进行的操作,帮助完成任务。除了文字列表外,还可以用图标+宫格式的展示方式,例如分享功能的多个选项。

执行潜在的破坏性操作前的二次确认:

当执行潜在的破坏性操作前需再做提醒,避免产生不可挽回的失误。需注意的是破坏性操作的按钮需重点突出,一般用红色,起到警示,危险的提醒作用

和alert的区别:

alert主要适用于两个选项,而actionsheet可以有多个功能选项,且展示形式更多样。前文讲过,alert也有破坏性操作提醒的场景使用。

两者相比,alert出现在屏幕中央,actionsheet出现在屏幕底部。视觉角度上alert相较于actionsheet更有阻断感,对用户而言干扰性更大。

另一方面底部的actionsheet从手势操作的角度上来看,操作更方便,更容易对此作出选择或关闭。所以alert更加适用于严重后果的破坏性操作提醒。

4.4 强干扰——activity view(活动视图)

活动视图是ios组件,是针对当前页面提供的一系列任务和服务,例如复制,收藏,查找等。系统提供了许多内置活动,包括打印,信息和AirPlay。

这些任务始终首先出现在活动视图中,无法重新排序。无需创建执行这些内置任务的自定义活动。活动视图还显示来自其他应用的共享和操作扩展。

4.5 强干扰类——modal bottom sheet(模态底部菜单)

Bottom sheet是MD的组件,MD中底部菜单有两种,一种是Standard bottom sheet(标准底部菜单),另一种是Modal bottom sheet(模态底部菜单)。

MD的模态底部菜单和iOS的action sheet类似,它阻止用户与屏幕其他地方交互,通过聚焦的底部菜单提供了更多的选项和功能。它可以是内联菜单和简单对话框的替代方案,为内容,图标和动作提供了额外的空间。

规范建议,模态底部淡淡的初始垂直位置的上限为屏幕高度的50%。内容超过屏幕高度50%的模态菜单可以在整个屏幕上拉动,在内部滚动以访问其余项目。同样他的展现方式有列表式,也可有宫格式

4.6 轻反馈——snackbar

snackbar是android专有控件,是出现在屏幕底部的提供有关app相关的简短信息提醒,它属于轻量级的信息提醒,一般出现几秒后就会自动消失,不会中断用户操作。

snackbar往往由一条文案+一个引导性按钮(可选,按钮可以引导用户进一步操作)组成,带有一定的交互性。因为它自动会消失,所以它一定没有取消或者不要等否定性按钮。

4.6.1 使用场景

传达轻量级的信息和操作反馈,可以引导用户操作:

传达轻量级的信息或反馈,并且可以引导用户进行下一步行为,但并不强制用户操作。比如chrome添加书签时,可以进一步对新加的书签进行编辑;删除书签时防止用户后悔,提供一个撤销按钮。

4.7 轻反馈——Toas

Toast是android专有的控件,原先的MD规范中,toast是和snackbar放在一起讲的,翻阅了最新的MD规范,snackbar里找不到关于toast的相关介绍(有小伙伴找到的望提醒一下)。

Toast应该包含在snackbar里了,当snackbar没有按钮其实就是toast了,不过这边还是把Toast单独拿出来分析

4.7.1 使用场景

传达轻量级的信息和操作反馈,且不需要用户操作:

适用于通知用户不重要的信息和操作反馈,且不会对用户当前的任务有影响,因为不能交互,且几秒后消失,所以用户很可能忽略,所以该类信息相对而言没那么重要。

虽然toast是android专有样式,但现在很多ios版本的系统中都使用了改良版的“toast”,因为轻反馈,不打断用户操作,同时又能通知信息和操作反馈,对用户而言及其友好,但是不易传达过多的文字,因为用户很有可能会忽略。

ios文档中的feedback中有建议:反馈可以帮助人们了解应用正在做什么,发现他们下一步可以做什么,并了解行动的结果。所以实际应用中,既要不打扰用户,又要能引起用户注意,还要和产品设计相协调。

比如结合了文字和icon的样式,再比如用较为突出的背景色,位置的话在中央,顶部,底部,都会出现,会根据具体的业务来选择合适的位置。一般出现的位置会和操作内容在一起,这样用户才能清晰有效地得到即时反馈。

下方例举的toast案例因为选用了比内容更为突出的背景色,相比较上方案例的toast更易被用户发现和察觉,达到通知用户的目的。

4.8 轻反馈——Hud

Hud透明指示层,ios专用控件,典型的就是音量调节的弹窗样式。部分改良的toast,在样式上有借鉴学习Hud。

五.总结

5.1 对比总结

Dialog/Alert:

当信息或操作非常重要,并且必须要由用户做决定或者操作才能继续,一般用alert,更适用于用户判断选择。

Modal bottom sheet/Action sheet:

稍弱于dialog/alert,更着重于提供更多的功能和选项时使用。

Activity view:

是针对当前页面提供的一系列额外的任务和服务。

Popover:

使用更侧重于指向性,更适用于信息或功能折叠。

Toast:

不太重要的信息提醒和操作反馈,更适用于不需用户响应或反馈的场景。

snackbar:

不太重要的信息提醒和操作反馈,可以交互,但并不强制,更适用于可以引导用户进行下一步或者一些撤销上一步的场景。

Hud:

音量调节。

5.2 其他

了解了每个弹窗组件的用法,下次就可以根据实际业务设计合适的弹窗了,不过官方规范或者文章的建议也都只是参考,实际工作中还是要灵活变通,设计的目标是帮助用户更好更快的解决问题。

以上就是我对弹窗相关知识的总结,总结的过程中也对官方规范弹窗部分的内容再次熟悉了好几遍,因为看的英文,所以理解上可能稍微有些不足,有不对的地方,还希望大家批评指正。(推荐大家多看看官方设计规范,就像一本非常实用的设计工具书,对于实际工作还是非常有帮助的)

六.参考资料

再次感谢前辈的经验分享!

这个控件叫什么系列之toast的曾经,现在,与未来 https://www.uisdc.com/ui-element-toast

如何设计App中的提示控件(toast) https://zhuanlan.zhihu.com/p/22405748

iOS和Android规范解析——底部浮层(上)https://www.jianshu.com/p/8bdfbc0a9339

iOS和Android规范解析——提示框(Toast)对比 https://www.jianshu.com/p/e1beeacbea32

不要滥用对话框!细说 iOS Alert View 与 Action Sheet https://zhuanlan.zhihu.com/p/20189186

App设计中,6组常见组件的区别和用法 http://www.woshipm.com/pd/873075.html

APP提示框架详解:Toast提示、Snackers和Alert http://www.woshipm.com/pmd/296674.html

本文由 @麦子_Maizi 原创发布于人人都是产品经理。未经许可,禁止转载

题图来自Unsplash,基于CC0协议