Cuando webview carga una página web en HarmonyOS, necesita una barra de progreso o una animación de carga para la interacción percibida por el usuario, lo que puede optimizar la experiencia del usuario, así que hoy escribí una animación de carga (el efecto es el siguiente) para que los estudiantes aprendan cómo ¿para lograrlo? En primer lugar, necesitamos aprender las tres reservas de conocimiento de " CommonDialog ", " WebView " y " Animation Development Guide "
Estamos divididos en "etapa de preparación", "implementación personalizada de CommonDialog", "implementación de animación", "implementación de vista web", "efecto de ejecución" cinco pasos para implementar.
1. Etapa de preparación
Prepare una imagen de carga (imagen a continuación) en el directorio de recursos \ base \ media \ y la ubicación de almacenamiento es la siguiente
Cargando imágenes
Ubicación de almacenamiento
2. Personaliza la implementación de CommonDialog
2.1 Cree un nuevo xml llamado general_dialog.xml y dibuje una imagen en el archivo xml (el código es el siguiente)
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="80vp"
ohos:orientation="vertical"
ohos:alignment="center"
ohos:width="80vp">
<Image
ohos:id="$+id:loading"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:scale_mode="clip_center"
ohos:image_src="$media:loading"/>
</DirectionalLayout>
El diagrama de efectos es el siguiente
2.2 Cree un nuevo archivo GeneralDialog, nos referimos al ejemplo de escena CommonDialog personalizado de HarmonyOS
El código específico es el siguiente
package com.harmony.alliance.mydemo.utils;
import java.util.Optional;
import com.harmony.alliance.mydemo.ResourceTable;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
public class GeneralDialog {
private float dim = -1f;
private CommonDialog sDialog;
private Context mContext;
private boolean mOutsideTouchClosable = false;
public GeneralDialog(Context context){
this.mContext=context;
}
public void show() {
if (sDialog != null) {
sDialog.show();
if (dim >= 0) {
changeDialogDim(sDialog, dim);
}
}
}
public void remove(){
if (sDialog != null) {
sDialog.destroy();
}
}
public void create() {
sDialog = new CommonDialog(mContext);
sDialog.setSize(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
sDialog.setAlignment(LayoutAlignment.CENTER);
sDialog.setOffset(0,0);
sDialog.setTransparent(true);
sDialog.setContentCustomComponent(initDialog(sDialog));
sDialog.setAutoClosable(mOutsideTouchClosable);
}
private void changeDialogDim(CommonDialog dialog, float dim) {
Optional<WindowManager.LayoutConfig> configOpt = dialog.getWindow().getLayoutConfig();
configOpt.ifPresent(config -> {
config.dim = dim;
dialog.getWindow().setLayoutConfig(config);
});
}
public interface ClickedListener{
void onClick(GeneralDialog dialog);
}
private Component initDialog(CommonDialog sDialog) {
Component dialogLayout = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_general_dialog, null, false);
dialogLayout.setBackground(new ShapeElement(){{
setRgbColor(RgbColor.fromArgbInt(ResourceTool.getColor(mContext, ResourceTable.Color_bg_dialog_light, 0xffffff)));
setCornerRadius(ResourceTool.getFloat(mContext, ResourceTable.Float_dialog_corner_radius, 0));
}});
Image image= (Image) dialogLayout.findComponentById(ResourceTable.Id_loading);
return dialogLayout;
}
}
2.2.3 Llame al siguiente código bajo el método onStart de MainAbility
GeneralDialog mGeneralDialog = new GeneralDialog(getContext());
mGeneralDialog.create();
mGeneralDialog.show();
El efecto es el siguiente
2.3 Implementación de animación
2.3.1 Función de animación Podemos consultar los puntos de conocimiento relevantes de AnimatorProperty en la guía de desarrollo de animación de HarmonyOS A continuación, iniciamos Diálogo para abrir el código de la función de animación de la imagen de la siguiente manera
Image image= (Image) dialogLayout.findComponentById(ResourceTable.Id_loading);
animatorProperty = new AnimatorProperty();
animatorProperty.setTarget(image);
animatorProperty
.rotate(360)
//无限循环
.setLoopedCount(AnimatorValue.INFINITE)
//反弹力效果
.setCurveType(Animator.CurveType.BOUNCE);
if(sDialog!=null){
sDialog.setDestroyedListener(new CommonDialog.DestroyedListener() {
@Override
public void onDestroy() {
if(animatorProperty.isRunning()){
animatorProperty.stop();
}
}
});
}
2.3.2 Escriba un método de animación abierto en la clase GeneralDialog (el código es el siguiente)
public void StartanimatorProperty(){
if(animatorProperty!=null&&animatorProperty.isRunning()){
animatorProperty.stop();
}
if(animatorProperty!=null&&!animatorProperty.isRunning()){
if(!animatorProperty.isRunning()){
animatorProperty.start();
}
}
}
2.3.3 Selle una clase de herramienta para mostrar, reproducir y desaparecer la ventana emergente de carga (el código es el siguiente)
package com.harmony.alliance.mydemo.utils;
import ohos.app.Context;
public class LoadingDialogUtils {
private static GeneralDialog mGeneralDialog;
public static GeneralDialog getInstance(Context mContext){
if(mGeneralDialog==null){
mGeneralDialog=new GeneralDialog(mContext);
}
return mGeneralDialog;
}
public static void show(Context mContext){
LoadingDialogUtils.getInstance(mContext);
mGeneralDialog.create();
mGeneralDialog.show();
mGeneralDialog.StartanimatorProperty();
}
public static void dismiss(Context mContext){
LoadingDialogUtils.getInstance(mContext);
mGeneralDialog.remove();
}
}
2.3.4 El código para abrir la animación es el siguiente
LoadingDialogUtils.show(MainAbility.this);
El código de animación de cierre es el siguiente
LoadingDialogUtils.dismiss(MainAbility.this);
2.4 Implementación de la vista web
webview carga páginas web, podemos referirnos a los componentes de WebView de HarmonyOS
2.4.1 Aprendemos a observar el setWebAgent del estado Web (el código es el siguiente)
webView.setWebAgent(new WebAgent() {
@Override
public void onLoadingPage(WebView webview, String url, PixelMap favicon) {
super.onLoadingPage(webview, url, favicon);
//todo 页面开始加载时自定义处理 开启动画
}
@Override
public void onPageLoaded(WebView webview, String url) {
super.onPageLoaded(webview, url);
// todo 页面加载结束后自定义处理 关闭动画
}
@Override
public void onLoadingContent(WebView webview, String url) {
super.onLoadingContent(webview, url);
// 加载资源时自定义处理
}
@Override
public void onError(WebView webview, ResourceRequest request, ResourceError error) {
super.onError(webview, request, error);
//todo 发生错误时自定义处理 关闭动画
}
});
2.4.2 Creamos una nueva clase Java de skillSlice, y el nuevo código de diseño es el siguiente
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<ohos.agp.components.webengine.WebView
ohos:id="$+id:my_webView"
ohos:height="match_parent"
ohos:width="match_parent">
</ohos.agp.components.webengine.WebView>
</DirectionalLayout>
2.4.3 El código de clase java de webview es el siguiente
package com.harmony.alliance.mydemo.slice;
import com.harmony.alliance.mydemo.ResourceTable;
import com.harmony.alliance.mydemo.utils.LoadingDialogUtils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.webengine.*;
import ohos.media.image.PixelMap;
public class NewMyWebview extends AbilitySlice {
private WebView mMyWebview;
private static final String EXAMPLE_URL = "https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-fa-calls-pa-examples-0000000000618000";
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
setUIContent(ResourceTable.Layout_new_my_webview);
mMyWebview= (WebView) findComponentById(ResourceTable.Id_my_webView);
WebConfig webConfig = mMyWebview.getWebConfig();
webConfig.setJavaScriptPermit(true);
webConfig.setWebStoragePermit(true);
webConfig.setDataAbilityPermit(true);
webConfig.setLoadsImagesPermit(true);
webConfig.setMediaAutoReplay(true);
webConfig.setLocationPermit(true);
webConfig.setSecurityMode(WebConfig.SECURITY_SELF_ADAPTIVE);
mMyWebview.setWebAgent(new WebAgent() {
@Override
public void onLoadingPage(WebView webview, String url, PixelMap favicon) {
super.onLoadingPage(webview, url, favicon);
//todo 页面开始加载时自定义处理 开启动画
LoadingDialogUtils.show(NewMyWebview.this);
}
@Override
public void onPageLoaded(WebView webview, String url) {
super.onPageLoaded(webview, url);
// todo 页面加载结束后自定义处理 关闭动画
LoadingDialogUtils.dismiss(NewMyWebview.this);
}
@Override
public void onLoadingContent(WebView webview, String url) {
super.onLoadingContent(webview, url);
// 加载资源时自定义处理
}
@Override
public void onError(WebView webview, ResourceRequest request, ResourceError error) {
super.onError(webview, request, error);
//todo 发生错误时自定义处理 关闭动画
LoadingDialogUtils.dismiss(NewMyWebview.this);
}
});
mMyWebview.load(EXAMPLE_URL);
}
}
2.5 El efecto de la operación es el siguiente
Todos los códigos son los siguientes
2.5.1 código general_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="80vp"
ohos:orientation="vertical"
ohos:alignment="center"
ohos:width="80vp">
<Image
ohos:id="$+id:loading"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:scale_mode="clip_center"
ohos:image_src="$media:loading"/>
</DirectionalLayout>
2.5.2 clase java de GeneralDialog
//请根据实际工程/包名引入
package com.harmony.alliance.mydemo.utils;
import java.util.Optional;
import com.harmony.alliance.mydemo.ResourceTable;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
public class GeneralDialog {
private float dim = -1f;
private AnimatorProperty animatorProperty;
private CommonDialog sDialog;
private Context mContext;
private boolean mOutsideTouchClosable = false;
public GeneralDialog(Context context){
this.mContext=context;
}
public void show() {
if (sDialog != null) {
sDialog.show();
if (dim >= 0) {
changeDialogDim(sDialog, dim);
}
}
}
public void remove(){
if (sDialog != null) {
sDialog.destroy();
}
}
public void create() {
sDialog = new CommonDialog(mContext);
sDialog.setSize(ComponentContainer.LayoutConfig.MATCH_CONTENT, ComponentContainer.LayoutConfig.MATCH_CONTENT);
sDialog.setAlignment(LayoutAlignment.CENTER);
sDialog.setOffset(0,0);
sDialog.setTransparent(true);
sDialog.setContentCustomComponent(initDialog(sDialog));
sDialog.setAutoClosable(mOutsideTouchClosable);
}
public void StartanimatorProperty(){
if(animatorProperty!=null&&animatorProperty.isRunning()){
animatorProperty.stop();
}
if(animatorProperty!=null&&!animatorProperty.isRunning()){
if(!animatorProperty.isRunning()){
animatorProperty.start();
}
}
}
private void changeDialogDim(CommonDialog dialog, float dim) {
Optional<WindowManager.LayoutConfig> configOpt = dialog.getWindow().getLayoutConfig();
configOpt.ifPresent(config -> {
config.dim = dim;
dialog.getWindow().setLayoutConfig(config);
});
}
public interface ClickedListener{
void onClick(GeneralDialog dialog);
}
private Component initDialog(CommonDialog sDialog) {
Component dialogLayout = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_general_dialog, null, false);
dialogLayout.setBackground(new ShapeElement(){{
setRgbColor(RgbColor.fromArgbInt(ResourceTool.getColor(mContext, ResourceTable.Color_bg_dialog_light, 0xffffff)));
setCornerRadius(ResourceTool.getFloat(mContext, ResourceTable.Float_dialog_corner_radius, 0));
}});
Image image= (Image) dialogLayout.findComponentById(ResourceTable.Id_loading);
animatorProperty = new AnimatorProperty();
animatorProperty.setTarget(image);
animatorProperty
.rotate(360)
//无限循环
.setLoopedCount(AnimatorValue.INFINITE)
//反弹力效果
.setCurveType(Animator.CurveType.BOUNCE);
if(sDialog!=null){
sDialog.setDestroyedListener(new CommonDialog.DestroyedListener() {
@Override
public void onDestroy() {
if(animatorProperty.isRunning()){
animatorProperty.stop();
}
}
});
}
return dialogLayout;
}
}
2.5.3 La clase de herramienta de LoadingDialogUtils es la siguiente
package com.harmony.alliance.mydemo.utils;
import ohos.app.Context;
public class LoadingDialogUtils {
private static GeneralDialog mGeneralDialog;
private static GeneralDialog getInstance(Context mContext){
if(mGeneralDialog==null){
mGeneralDialog=new GeneralDialog(mContext);
}
return mGeneralDialog;
}
public static void show(Context mContext){
LoadingDialogUtils.getInstance(mContext);
mGeneralDialog.create();
mGeneralDialog.show();
mGeneralDialog.StartanimatorProperty();
}
public static void dismiss(Context mContext){
LoadingDialogUtils.getInstance(mContext);
mGeneralDialog.remove();
}
}
2.5.4 El código xml del diseño de webViewAbilitySlice es el siguiente
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:orientation="vertical">
<ohos.agp.components.webengine.WebView
ohos:id="$+id:my_webView"
ohos:height="match_parent"
ohos:width="match_parent">
</ohos.agp.components.webengine.WebView>
</DirectionalLayout>
2.5.5 El código de clase de WebViewAbiltySlice es el siguiente
package com.harmony.alliance.mydemo.slice;
import com.harmony.alliance.mydemo.ResourceTable;
import com.harmony.alliance.mydemo.utils.LoadingDialogUtils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.webengine.*;
import ohos.media.image.PixelMap;
public class NewMyWebview extends AbilitySlice {
private WebView mMyWebview;
private static final String EXAMPLE_URL = "https://developer.harmonyos.com/cn/docs/documentation/doc-references/js-apis-fa-calls-pa-examples-0000000000618000";
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
setUIContent(ResourceTable.Layout_new_my_webview);
mMyWebview= (WebView) findComponentById(ResourceTable.Id_my_webView);
WebConfig webConfig = mMyWebview.getWebConfig();
webConfig.setJavaScriptPermit(true);
webConfig.setWebStoragePermit(true);
webConfig.setDataAbilityPermit(true);
webConfig.setLoadsImagesPermit(true);
webConfig.setMediaAutoReplay(true);
webConfig.setLocationPermit(true);
webConfig.setSecurityMode(WebConfig.SECURITY_SELF_ADAPTIVE);
mMyWebview.setWebAgent(new WebAgent() {
@Override
public void onLoadingPage(WebView webview, String url, PixelMap favicon) {
super.onLoadingPage(webview, url, favicon);
//todo 页面开始加载时自定义处理 开启动画
LoadingDialogUtils.show(NewMyWebview.this);
}
@Override
public void onPageLoaded(WebView webview, String url) {
super.onPageLoaded(webview, url);
// todo 页面加载结束后自定义处理 关闭动画
LoadingDialogUtils.dismiss(NewMyWebview.this);
}
@Override
public void onLoadingContent(WebView webview, String url) {
super.onLoadingContent(webview, url);
// 加载资源时自定义处理
}
@Override
public void onError(WebView webview, ResourceRequest request, ResourceError error) {
super.onError(webview, request, error);
//todo 发生错误时自定义处理 关闭动画
LoadingDialogUtils.dismiss(NewMyWebview.this);
}
});
mMyWebview.load(EXAMPLE_URL);
}
}
El efecto es el siguiente