当下主流 APP , Hybrid app 中需要熟练掌握的交互
如果感觉略有用处,点赞支持下作者。上一篇将关于 WebView 的设置仔细的捋了一遍,我们通过 WebViewController 这个类完成了所有 WebView 的设置,并且在布局的时候,只需在布局文件中引入这个类的完整包名,前提是这个类要继承于 WebView,就可以完成所有 WebView 的设置,具体可参考上一篇 当下主流 APP,Hybrid app 中需要熟练掌握的交互知识(一) 其实有人就说到了,现在有现成的框架可,那我的出发点是从自己动手开始,再去接触框架,这个系列我们一步步来!
那么本篇将就以下几点展开:
-
页面布局相同情况下Activity 的 共用问题。
-
在原生与网页混合的开发状态下,如何确定页面跳转以及参数传递。
-
根据服务端发送的 Js 接口名去做具体实现
Activity 共用
这是当下很多 WebApp 都在使用的一个套路,除了避免了创建多个 Activity 后影响性能之外,还可以保持项目「友好」的结构!这样的处理大多适应于这样的场景:
-
页面布局上方只有一个 ToolBar 或者 ActionBar 等等的标题栏
-
下方则是一个 WebView 用于呈现网页内容
-
如此则可以将共同的属性提取出来,WebView 则不用管,都是一致的东西。ToolBar 上无论是标题还是按钮的设置,当点击了某处后我们会进入我们在本地实现的网页接口,具体的原理请看下面的详细解释!
一 、建立共用的 Activity:
我们将之命名为 NewWebViewActivity
//获取到消息处理类传过来的 url 网址
String url = getIntent().getStringExtra("url");
//获取到消息处理类传过来的动画操作
int anim = getIntent().getIntExtra("animation", 0);
if (url == null) {
finish();
}else if (url.equals(Constants.urlHostBase + Constants.urlLogIn)){
baseWebView.loadUrl(url);
topToolbar.setVisibility(View.GONE);
} else {
baseWebView.loadUrl(url);
//用动画文件判断新开页面
if (anim == R.anim.slide_right_out) { //当所有的新开页面 是从右往左打开时(表示新开页面)
//添加返回按钮
backImageView.setImageResource(R.drawable.returns);
//变为显示状态
backImageView.setVisibility(View.VISIBLE);
//返回键点击事件
backImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish(); //关闭页面
//设置页面退出动画为从左往右退出
overridePendingTransition(R.anim.none, R.anim.slide_right_out);
}
});
}
}
可以看到,并没有多少逻辑。我们这样就可以所有新开的页面添加一个返回键了,前提是有一个消息处理的类来完成打开页面的 url 参数设置,以及动画参数设置,其实实现起来也是很简单!往下看
二 、建立共用的 Activity 的布局:
我们紧接着需要将我们这个 Activity 布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_new_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:theme="@android:style/Animation.Toast"
android:background="@android:color/white"
tools:context="com.lansum.eip.activity.NewWebViewActivity">
<!-- 标题栏 -->
<android.support.v7.widget.Toolbar
android:id="@+id/web_top_toolbar"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_alignParentTop="true"
android:background="#00a6ff"/>
<!-- WebView -->
<com.lansum.eip.webview.WebViewController
android:id="@+id/base_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/web_top_toolbar" />
<!-- 标题栏右上角图片点击按钮 默认隐藏状态 下同 -->
<ImageView
android:id="@+id/right_Button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignRight="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginRight="16dp"
android:layout_marginTop="30dp"
android:visibility="gone" />
<!-- 标题栏正中显示的标题 根据点击区域切换标题内容 -->
<TextView
android:id="@+id/toolbar_text_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:textColor="@android:color/white"
android:textSize="18sp" />
<!-- 标题栏左上角用于关闭打来页面的图片按钮 -->
<ImageView
android:id="@+id/back_web"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignLeft="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginLeft="16dp"
android:layout_marginTop="30dp"
android:visibility="gone" />
<!-- 右上角文字点击按钮 -->
<TextView
android:id="@+id/right_Button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginRight="16dp"
android:layout_marginTop="32dp"
android:textColor="@android:color/white"
android:textSize="18sp"
android:visibility="gone" />
</RelativeLayout>
布局文件很简单,我们将标题栏上正中标题,左上角关闭页面的图片点击按钮,右上角的文字提交按钮以及图片点击按钮都放在了布局中,那接下来就是如何去控制他们的显示时机,以及按下后的反馈了!
建立好了这个用于展示我们所有网页的共用 Activity 后,就是我们本篇的核心类了,敲黑板!!
核心类 HtmlMessageForLocal
在开始之前我们先将思路捋清楚
-
处理所有网页的接口实现,以及跳转操作和添加标题栏上的按钮添加。
-
此类用于接收我们点击或打开 WebView 服务端暴漏给我们的接口,我们负责具体实现!
-
将我们实现的方法上加上 @JavascriptInterface 注解
-
此注解表明所有服务端 Js 接口,都会进入我们自定义的这个方法里找同名方法,直接执行里面的逻辑!
好了,通过以上说明相信明眼的你可以发现,这是一个网页与我们本地的交互的核心类,所有的交互逻辑实现都需要在这里进行!
接下来我们分层进行,一层层,一个个方法的具体实现步骤,来剖析整个过程。
一 、判断接口名执行具体的方法:
@JavascriptInterface
public void callHandler(final String methodName, final String data, final String callbackName) {
Log.e(TAG, "Method:" + methodName);
if (methodName.equals("openAttendanceFromJS")) {
openAttendanceFromJS(data); // 打开新窗口
}
}
这里只是起到了判断作用,特定的方法执行特定的操作,就比如上面这个方法,只负责用户点击了 WebView 去打开新的 WebView 的所有操作。
如何判断
/**
* Js 与 Native(android 原生交互)
* Native 调用 JS 方法
* @param methodName Js 方法名
* @param data 需要用到的数据 比如图片资源需要传递的数据 以下代码的实体类为 RightInfo
我们需要声明一个实体类 用到什么数据资源就传给这个参数
* @param callbackName 回调的方法名 这里具体用不到
*/
@JavascriptInterface
public void callHandler(final String methodName, final String data, final String callbackName) {
Log.e(TAG, "Method:" + methodName);
if (methodName.equals("openAttendanceFromJS")) {
openAttendanceFromJS(data); // 打开新窗口
} else if (methodName.equals("addRightBarButtonItemFromJS")) {
addRightBarButtonItemFromJS(data);// 添加右上角按钮
}
/**
* 打开新窗口
* @param url
*/
protected void openAttendanceFromJS(String url) {
Log.i("js", url);
// TODO Auto-generated method stub
Intent intent = new Intent(ActivityCollector.getTopActivity(), NewWebViewActivity.class);
intent.putExtra("url", url);
intent.putExtra("animation", R.anim.slide_right_out);
intent.putExtra("animation", R.anim.slide_right_in);
ActivityCollector.getTopActivity().startActivity(intent);
}
/**
* 设置右上角图片按钮
* @param data
*/
protected void addRightBarButtonItemFromJS(String data) {
topRightImage.setBackgroundResource(imageId); //找到图片按钮资源
topRightImage.setVisibility(View.VISIBLE); //设置为可见状态
topRightImage.setOnClickListener(new View.OnClickListener() { //此按钮点击事件
@Override
public void onClick(View v) {
Activity activity = ActivityCollector.getTopActivity();//获取到栈顶 Activity
activity.runOnUiThread(new Runnable() { //强制运行到主线程
@Override
public void run() {
//找到共用打的 WebView
ActivityCollector.getTopActivity().findViewById(R.id.base_web_view);
activity.overridePendingTransition(R.anim.push_bottom_out, R.anim.push_bottom_in);
//找到对应 web url网址
baseWebView.loadUrl("javascript:" + rightInfo.funcName);
}
});
}
});
}
在这里用两个方法举例,重要的步骤在这里都呈现了出来,根据我们服务端和 Android 端的需求做相应逻辑和方法的叠加就可以了!
总结
此次在这里将 Js 与 Native 的交互做了一个简单总结记录,整理了通用流程和思想,下个系列将使用当下比较流行的 Hybrid APP 框架来实现一个总体的处理流程。