继上次使用自定义TextView展示内容后,产品觉得效果不太好,不能动态添加分隔线,这不,又要求我做更智能一些,怀着不断学习和为公司着想的理念,我又有了一个大胆的想法:使用跨语言实现。就是使用Html加一些JS代码来实现界面渲染功能。
自从有了ChatGPT,我在开发中有些麻烦和困扰经常也都能被解决掉,这次我就是让ChatGPT帮我写了一个Html代码,实现了一个类似如下界面的功能。
自定义textview中添加分割线真心有困难,不能通过Html中的
标签实现,所以我干脆直接使用WebView展示一段文本,文本内容由自己加Html标签实现。
创建一个Html文件,并实现插入文本,控制内容边距等功能
该文件我就全名为:show_text.html吧
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>文本展示</title>
<style>
/* 设置body内边距为0 */
body {
padding: 0;
margin: 0;
}
/* 设置p标签的左右margin为5 */
p {
margin-left: 5px;
margin-right: 5px;
}
/* 定义分隔线样式 */
.separator {
border: none; /* 去掉边框 */
height: 15px; /* 设置高度为15px */
background-color: #f2f2f2; /* 设置背景颜色为灰色 */
margin: 0; /* 设置上下边距为10px,左右边距为0 */
padding: 0;
}
/* 定义旋转动画 */
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* 定义loading图片样式 */
.loading-img {
width: 20px; /* 设置图片宽度 */
height: 20px; /* 设置图片高度 */
animation: spin 1s linear infinite; /* 应用旋转动画 */
}
/* 定义loading布局样式 */
.loading-layout {
height: 50px; /* 设置高度为100px */
/*background-color: white;*/ /* 设置背景颜色为白色 */
display: flex; /* 使用flex布局 */
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
}
</style>
</head>
<body style="">
<div id="content"></div>
<script>
function appendText(text) {
var div = document.getElementById('content');
div.innerHTML += text;
// 计算更新后的内容高度
// var newHeight = document.body.scrollHeight;
setTimeout(
function(){
var newHeight = div.offsetHeight;
jsbridge.updateHeight(newHeight);
},100
);
}
// 创建loading布局
function addLoadingLayout() {
var loadingDiv = document.createElement('div');
loadingDiv.classList.add('loading-layout'); // 添加loading布局样式
var spinner = document.createElement('img');
spinner.src = 'loading_img.png'; // 设置图片路径
spinner.classList.add('loading-img'); // 添加loading图片样式
loadingDiv.appendChild(spinner);
// 创建loading文本
var loadingText = document.createElement('p');
loadingText.textContent = '-The End-'; // 设置文本内容
//loadingText.style.color = 'black'; // 设置文本颜色
loadingText.style.fontFamily = 'Arial, sans-serif'; // 设置字体
loadingText.style.display = 'none'; // 默认隐藏文本
loadingDiv.appendChild(loadingText);
document.body.appendChild(loadingDiv);
return {
showImage: function() {
spinner.style.display = 'block'; // 显示图片
loadingText.style.display = 'none'; // 隐藏文本
},
showText: function() {
spinner.style.display = 'none'; // 隐藏图片
loadingText.style.display = 'block'; // 显示文本
}
};
}
// 创建loading布局并保存引用
var loadingLayout = addLoadingLayout();
loadingLayout.showImage();
</script>
</body>
</html>
最重要的就是这段代码了
<div id="content"></div>
<script>
function appendText(text) {
var div = document.getElementById('content');
div.innerHTML += text;
// 计算更新后的内容高度
// var newHeight = document.body.scrollHeight;
setTimeout(
function(){
var newHeight = div.offsetHeight;
umenovel.updateHeight(newHeight);
},100
);
}
</script>
主要通过调用appendText方法不段往content这个段落中添加文本,并在添加完后获取当前webview中内容的高度。
实现webview加载该html文件
- 在Activity中布局内加入一个webview组件,用于加载Html文件。
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".book.novelreadmodel.NovelReadActivity">
<WebView
android:id="@+id/webview_read"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
- 在Activity中初始化该WebView,并设置允许使用javascript能力。
public class DemoActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView mReadWebView = findViewById(R.id.webview_read);
// 加入下面两段可以在本webview中显示网页,不会打开跳转到系统浏览器
mReadWebView.setWebChromeClient(new WebChromeClient() {
});
mReadWebView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
});
mReadWebSettings = mReadWebView.getSettings();
mReadWebSettings.setJavaScriptEnabled(true);
mReadWebSettings.setSupportZoom(false);
mReadWebSettings.setBuiltInZoomControls(false);
mReadWebSettings.setDefaultFontSize(mTextSize);
// 拉回桥接接口
ReadModelJsBridge readModelJsBridge = new ReadModelJsBridge();
mReadWebView.addJavascriptInterface(readModelJsBridge, "jsbridge");
}
}
桥接对象中处理获取内容高度的回调。如下:
@Keep
public class ReadModelJsBridge {
/**
* 更新Html中内容的高度
*/
@JavascriptInterface
public void updateHeight(int contentHeight) {
}
}
webview加载本地html文件
将show_text.html文件放到assets目录下,如果有loading图片也放到html相同目录下。
在调用该文件时使用如下语句,展示到webview中:
mReadWebView.loadUrl("file:///android_asset/html/show_text.html");
在界面加载完毕后,就可以使用webview.loadUrl方法或webview.evaluateJavascript方法进行加载或执行javascript脚本:
// 调用添加文本方法
// conten为文本内容,可以为html标签的文本也可以是普通文本
webview.loadUrl("javascript:appendText('" + content + "')");
// 显示底部加载的loading图片
webview.evaluateJavascript("loadingLayout.showText();", null)
// 调用底部显示文本
webview.evaluateJavascript("loadingLayout.showImage();", null)
给Html添加文本
给Html添加文本时,一般有标题、内容和分割线,此处在一个方法中直接编辑好插入,代码如下所示:
// 先处理文本
private String appendHtmlText(String title, String htmlText) {
StringBuilder htmlContent = new StringBuilder();
// title添加到文本中
if (!TextUtils.isEmpty(title)) {
String formatHtmlTitle = "<h1>" + title.trim() + "</h1>";
htmlContent.append(formatHtmlTitle);
}
// 添加HTML文本到TextView中
htmlContent.append(htmlText);
if (htmlContent.length() > 0) {
// 如果已经有文本内容,则添加换行
htmlContent.append("<br>");
}
// 根据上面html中对separator的样式定义,这里可直接在文本后加入一个<div>标签
htmlContent.append("<div class=\"separator\"></div>");
return htmlContent.toString();
}
通过上面这段代码可以初步构建出一个Html文本,再通过上面提到的使用webview.loadUrl来加载html中的方法。
String content = appendHtmlText("我是个title","我是个内容");
mReadWebView.post(() -> mReadWebView.loadUrl("javascript:appendText('" + content + "')"));
修改Html中body的背景色
在修改webview背景色的时候通常可以直接设置webview.setbackgroundResource,但也可以通过修改body的背景色来实现。如下:
mReadWebView.evaluateJavascript("document.body.style.backgroundColor = '" + colorStr + "';", null)
此处的colorStr一般为十六进制色值,如:#FFFFFF,#f2f2f2
也可以通过将一个color.xml中的颜色id值转换成十六进制字符串型。
// 颜色转换
private String formatColor(int colorId) {
// int color = ContextCompat.getColor(this, colorId);
String hexColor = String.format("#%06X", (0xFFFFFF & colorId));
return hexColor;
}
// 设置背景色
private void setWebViewBackground(int color) {
if (mReadWebView != null && color != 0) {
String colorStr = formatColor(ContextCompat.getColor(this, color));
mReadWebView.post(() -> mReadWebView.evaluateJavascript("document.body.style.backgroundColor = '" + colorStr + "';", null));
}
}
// 调用setWebViewBackground(int color)
setWebViewBackground(R.color.color_background);// color_background为color.xml中的色值
修改Html内body中的文本颜色
private void setWebViewTextColor(String colorStr) {
if (mReadWebView != null) {
mReadWebView.post(() -> mReadWebView.evaluateJavascript("document.body.style.color = '" + colorStr + "';", null));
}
}
如果想设置color.xml颜色,可以查看上面设置body背景色中的方法进行转换后设置。
修改webview中内容的字体大小
通过获取websettings设置setDefaultFontSize(int size)。
默认大小为16,介于1和72之间的非负整数。指定范围之外的任何数字都将被固定
// textsize为整数
mReadWebSettings.setDefaultFontSize(mTextSize);
目前项目中也就暂时只用到这几个常见的功能,如果需要更多功能也请留言,我将尽量完善博客,第一次自己写一个html在android中实现这种效果,还有不足之处,请大家指教。