Compose和Android View相互使用

文章目录

  • Compose和Android View相互使用
    • 在Compose中使用View
      • 概述
      • 简单控件
      • 复杂控件
      • 嵌入XML布局
    • 在View中使用Compose
      • 概述
      • 在Activity中使用Compose
      • 在Fragment中使用Compose
        • 布局使用多个ComposeView
      • 在布局中使用Compose
    • 组合使用

Compose和Android View相互使用

在Compose中使用View

概述

Compose是一个全新的UI框架,虽然重写了我们熟悉的很多控件,但不可能面面俱到,比如Android View中的一些复杂控件Compose并没有重写。

简单控件

属性:

@Composable
@UiComposable
fun <T : View> AndroidView(factory: (Context) -> T, // Android Viewmodifier: Modifier = Modifier, // 修饰符update: (T) -> Unit = NoOpUpdate // 加载布局后回调
)

使用:

在这里插入图片描述

AndroidView(factory = { CalendarView(it) },modifier = Modifier.fillMaxSize(),update = {it.setOnDateChangeListener { view, year, month, dayOfMonth ->Toast.makeText(view.context, "${year}${month}${dayOfMonth}日", Toast.LENGTH_SHORT).show()}}
)

复杂控件

使用WebView、MapView等控件时需要在对应生命周期中调用对应方法,否则会引起内存泄漏。

在 Compose 中如果需要根据生命周期来进行不同操作,就需要使用 LocalLifecycleOwner。通过 LocalLifecycleOwner 可以获取当前的lifecycle,然后在控件创建的时候加上监听,之后在关闭的时候关掉监听。

@Composable
fun rememberWebViewWithLifecycle(): WebView {val context = LocalContext.currentval webView = remember {WebView(context)}val lifecycleObserver = rememberWebViewLifecycleObserve(webView)val lifecycle = LocalLifecycleOwner.current.lifecycleDisposableEffect(lifecycle) {lifecycle.addObserver(lifecycleObserver)onDispose {lifecycle.removeObserver(lifecycleObserver)}}return webView
}@Composable
fun rememberWebViewLifecycleObserve(webView: WebView): LifecycleEventObserver {return remember(webView) {LifecycleEventObserver { source, event ->when (event) {Lifecycle.Event.ON_RESUME -> webView.onResume()Lifecycle.Event.ON_PAUSE -> webView.onPause()Lifecycle.Event.ON_DESTROY -> webView.destroy()else -> android.util.Log.e("TAG", "hello world")}}}
}@SuppressLint("SetJavaScriptEnabled")
@Composable
fun MyAndroidView() {val webView = rememberWebViewWithLifecycle()AndroidView(factory = { webView },modifier = Modifier.fillMaxSize(),update = { webView ->webView.settings.apply {javaScriptEnabled = true}webView.loadUrl("https://www.baidu.com")})
}

嵌入XML布局

如果大家在重构项目时遇到复杂的XML布局不易使用Compose来构建,也可以直接在Compose中使用XML布局,不过Compose目前只支持以ViewBinding的方式构建的XML布局。

开启ViewBinding:

viewBinding {enabled = true
}

添加依赖库:

implementation "androidx.compose.ui:ui-viewbinding:1.3.0-beta02"

属性:

fun <T : ViewBinding> AndroidViewBinding(// 创建ViewBindingfactory: (inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean) -> T,// 修饰符modifier: Modifier = Modifier,// 加载完后回调update: T.() -> Unit = {}
) 

使用:

在这里插入图片描述

login_layout.xml

<?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:orientation="vertical"><EditTextandroid:id="@+id/et_name"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="30dp"android:hint="name" /><EditTextandroid:id="@+id/et_password"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginHorizontal="30dp"android:hint="password" /><Buttonandroid:id="@+id/btn_login"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginTop="30dp"android:text="登录" />
</LinearLayout>

MainActivity

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {Scaffold() { paddingValues ->Box(modifier = Modifier.padding(paddingValues)) {MyAndroidXml()}}}}fun doLogin(name: String, password: String) {if (name.isEmpty() || password.isEmpty()) {Toast.makeText(this, "用户名密码不能为空", Toast.LENGTH_SHORT).show()return}Toast.makeText(this, "用户名:$name 密码:$password", Toast.LENGTH_SHORT).show()}
}@Composable
fun MyAndroidXml() {val context = LocalContext.current as MainActivityAndroidViewBinding(factory = { inflater, parent, attachToParent ->LoginLayoutBinding.inflate(inflater, parent, attachToParent)},modifier = Modifier.fillMaxSize(),update = {btnLogin.setOnClickListener {val name = etName.text.toString().trim()val password = etPassword.text.toString().trim()context.doLogin(name, password)}})
}

在View中使用Compose

概述

在 Android View 中也可以使用 Compose,平时编写 Android 代码的时候一般会使用 Activity 或 Fragment 来展示页面。

在Activity中使用Compose

添加依赖库:

如果是新建的Compose项目,编译器会直接帮我们引入 activity-compose 的依赖;如果是老项目,就需要我们手动添加依赖。

implementation 'androidx.activity:activity-compose:1.3.1'

通过 setContent 方式使用 Compose。

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {Text("hello world")}}
}

在Fragment中使用Compose

class MyFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View {val composeView = ComposeView(requireContext()).apply {setContent {Text("hello world")}}return composeView}
}
布局使用多个ComposeView

如果一个布局中存在多个ComposeView,那么每个ComposeView必须有唯一ID才能使saveInstanceState发挥作用。

class MyFragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View {val linearLayout = LinearLayout(requireContext()).apply {orientation = LinearLayout.VERTICALval oneComposeView = ComposeView(requireContext()).apply {id = R.id.compose_onesetContent {Text("hello")}}addView(oneComposeView)val button = Button(requireContext()).apply {text = "world"}addView(button)val twoComposeView = ComposeView(requireContext()).apply {id = R.id.compose_twosetContent {Text("compose")}}addView(twoComposeView)}return linearLayout}
}

在布局中使用Compose

  • 在XML布局中使用ComposeView。
  • 通过ComposeView的setContent设置Compose组件。

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><EditTextandroid:id="@+id/et_input"android:layout_width="match_parent"android:layout_height="wrap_content"android:padding="30dp" /><androidx.compose.ui.platform.ComposeViewandroid:id="@+id/compose_view"android:layout_width="match_parent"android:layout_height="wrap_content" /></LinearLayout>

代码:

class MainActivity : AppCompatActivity() {private lateinit var activityMainBinding: ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)activityMainBinding = ActivityMainBinding.inflate(layoutInflater)setContentView(activityMainBinding.root)initViews()}private fun initViews() {activityMainBinding.apply {composeView.setContent {var content by remember { mutableStateOf("") }Column(modifier = Modifier.fillMaxSize()) {Button(onClick = { content = etInput.text.toString().trim() }) {Text("提交")}Text(content)}}}}
}

组合使用

目前大部分应用都是基于 Android View 编写的,而 Android View 只能显示 View,因此需要将 Compose 转为 Android View 中使用的 View。

第一步:创建Compose

@Composable
fun rememberWebViewWithLifecycle(): WebView {val context = LocalContext.currentval webView = remember {WebView(context)}val lifecycleObserver = rememberWebViewLifecycleObserve(webView)val lifecycle = LocalLifecycleOwner.current.lifecycleDisposableEffect(lifecycle) {lifecycle.addObserver(lifecycleObserver)onDispose {lifecycle.removeObserver(lifecycleObserver)}}return webView
}@Composable
fun rememberWebViewLifecycleObserve(webView: WebView): LifecycleEventObserver {return remember(webView) {LifecycleEventObserver { source, event ->when (event) {Lifecycle.Event.ON_RESUME -> webView.onResume()Lifecycle.Event.ON_PAUSE -> webView.onPause()Lifecycle.Event.ON_DESTROY -> webView.destroy()else -> android.util.Log.e("TAG", "hello world")}}}
}@SuppressLint("SetJavaScriptEnabled")
@Composable
fun WebViewPage() {val webView = rememberWebViewWithLifecycle()AndroidView(factory = { webView },modifier = Modifier.fillMaxSize(),update = { webView ->webView.settings.apply {javaScriptEnabled = true}webView.loadUrl("https://www.baidu.com")})
}

第二步:将Compose转为Android View

class MyAndroidView @JvmOverloads constructor(context: Context,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : AbstractComposeView(context, attrs, defStyleAttr) {@Composableoverride fun Content() {WebViewPage()}
}

第三步:使用Android View

<com.example.app222.MyAndroidViewandroid:layout_width="match_parent"android:layout_height="match_parent" />

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/314489.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB的几种边缘检测算子(Sobel、Prewitt、Laplacian)

MATLAB的几种边缘检测算子(Sobel、Prewitt、Laplacian) clc;close all;clear all;warning off;%清除变量 rand(seed, 100); randn(seed, 100); format long g;% 读取图像 image imread(lena.png); % 转换为灰度图像 gray_image rgb2gray(image); % 转换为double类型以进行计算…

【视频异常检测】Open-Vocabulary Video Anomaly Detection 论文阅读

Open-Vocabulary Video Anomaly Detection 论文阅读 AbstractMethod3.1. Overall Framework3.2. Temporal Adapter Module3.3. Semantic Knowledge Injection Module3.4. Novel Anomaly Synthesis Module3.5. Objective Functions3.5.1 Training stage without pseudo anomaly …

滚动条详解:跨平台iOS、Android、小程序滚动条隐藏及自定义样式综合指南

滚动条是用户界面中的图形化组件&#xff0c;用于指示和控制内容区域的可滚动范围。当元素内容超出其视窗边界时&#xff0c;滚动条提供可视化线索&#xff0c;并允许用户通过鼠标滚轮、触屏滑动或直接拖动滑块来浏览未显示部分&#xff0c;实现内容的上下或左右滚动。它在保持…

(四)Servlet教程——Maven的安装与配置

1.在C盘根目录下新建一个Java文件夹,该文件夹用来放置以下步骤下载的Maven&#xff1b; 2. 下载Maven的来源有清华大学开源软件镜像站和Apache Maven的官网&#xff0c;由于清华大学开源软件镜像站上只能下载3.8.8版本以上的Maven&#xff0c;我们选择在Apache Maven的官网上下…

OpenWrt里面运行docker安装windows xp

stdout: ❯ Starting Windows for Docker v2.20... stdout: ❯ For support visit https://github.com/dockur/windows stdout: ❯ CPU: Intel Xeon CPU E3 1230 V2 stdout: Intel Xeon CPU E3 1230 V2 | RAM: 7/7 GB | DISK: 416 GB (ext4) | HOST: 5.15.34... stdout: stdou…

UE4网络图片加载库(带内存缓存和磁盘缓存)

UE4网络图片加载库,带内存缓存和磁盘缓存,支持自定义缓存大小,支持蓝图和C++代码调用 1、调用示例 2、对外暴露函数 3、源代码-网络模块 KeImageNet.h // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreM…

zabbix6.4告警配置(短信告警和邮件告警),脚本触发

目录 一、前提二、告警配置1.邮件告警脚本配置2.短信告警脚本配置3.zabbix添加报警媒介4.zabbix创建动作4.给用户添加报警媒介 一、前提 已经搭建好zabbix-server 在需要监控的mysql服务器上安装zabbix-agent2 上述安装步骤参考我的上篇文章&#xff1a;通过docker容器安装za…

printjs打印表格的时候多页的时候第一页出现空白

现象&#xff1a;打印多页的时候第一页空白了&#xff0c;一页的时候没有问题 插件&#xff1a;printjs 网上搜索半天找到的方式解决&#xff1a; 1. 对于我这次的现象毫无作用。其他情况不得而知&#xff0c;未遇见过。&#xff08;这个应该是大家用的比较多的方式&#xf…

检测水箱水位传感器有哪些?

生活中很多家电中都内含一个水箱&#xff0c;例如电蒸锅、饮水机、蒸汽熨斗、咖啡机等等&#xff0c;这些内部都有水箱&#xff0c;或大或小。当然水箱也有很多种类型&#xff0c;例如生活水箱、生产水箱、消防水箱等等。 把水储存在水箱中也会遇到这些问题&#xff0c;水箱没…

CSS学习(选择器、盒子模型)

1、CSS了解 CSS&#xff1a;层叠样式表&#xff0c;一种标记语言&#xff0c;用于给HTML结构设置样式。 样式&#xff1a;文字大小、背景颜色等 p标签内不能嵌套标题标签。 px是相对于分辨率而言的&#xff0c; em是相对于浏览器的默认字体&#xff0c; rem是相对于HTML根元…

nvm的下载与安装

nvm&#xff08;Node Version Manager&#xff09;是一个用于管理 Node.js 版本的工具&#xff0c;它允许您在同一台计算机上安装和切换不同的 Node.js 版本。 一、下载地址 https://github.com/coreybutler/nvm-windows/releases 二、安装nvm 三、设置环境变量 在命令提示…

一、Django 初识

简介 Django 是一个用于构建 Web 应用程序的高级 Python Web 框架。 版本对应 不同版本的django框架是基于特定的不同的python版本开发的&#xff0c;所以不同版本的django框架要正常执行功能只能安装特定的python版本 Django安装 安装 Django # 全局安装 pip install dj…

频率分析和离散傅里叶变换——DSP学习笔记四

背景知识 四种基本的傅里叶变换 基本思想&#xff1a;将信号表示为不同频率 正弦分量的线性组合 正弦信号和复指数时间信号的有用特性 相同频率但不同相位的正弦信号的任何线性组合&#xff0c;都是有着相同频率但不同相位&#xff0c;且幅度可能受改变的正弦信号。 复指数时…

软件物料清单(SBOM)生成指南 .pdf

如今软件安全攻击技术手段不断升级&#xff0c;攻击数量显著增长。尤其是针对软件供应链的安全攻击&#xff0c;具有高隐秘性、追溯难的特点&#xff0c;对企业软件安全威胁极大。 同时&#xff0c;软件本身也在不断地更新迭代&#xff0c;软件内部成分安全性在持续变化浮动。…

【算法】人工蜂群算法,解决多目标车间调度问题,柔性车间调度问题

文章目录 复现论文什么是柔性作业车间调度问题&#xff1f;数据处理ABC算法编码解码种群初始化雇佣蜂操作IPOX交叉多点交叉 观察蜂操作侦察蜂操作算法流程 结果程序截图问询、帮助 复现论文 什么是柔性作业车间调度问题&#xff1f; 也叫多目标车间调度问题。 柔性作业车间调…

为什么有的晶圆厂叫特色工艺晶圆厂?

知识星球&#xff08;星球名&#xff1a; 芯片制造与封测社区&#xff09;里的学员问&#xff1a; 经常看看到某某晶圆厂是12英寸特色工艺晶圆厂&#xff0c;特色工艺是指什么&#xff1f; 芯片的种类&#xff1f; 芯片分为四大类:mems,IC,光电器件&#xff0c;分立器件。 …

web(微博发布案例)

示例&#xff1a; 1、检测空白内容 2、发布内容 html: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta …

科蓝尔环保 | 成都2024全国水科技大会暨技术装备成果展览会

2024年5月13日一15日中华环保联合会、福州大学、上海大学在四川省成都市联合举办“2024全国水科技大会暨技术装备成果展览会”。 大会主题&#xff1a;加快形成新质生产力 增强水业发展新动能 大会亮点&#xff1a;邀请6位院士&#xff0c;100余位行业专家&#xff0c;15场专…

Redis缓存问题:穿透,击穿,雪崩等

Redis缓存问题:穿透,击穿,雪崩等 在高并发场景下,数据库往往是最薄弱的环节,我们通常选择使用redis来进行缓存,以起到缓冲作用,来降低数据库的压力,但是一旦缓存出现问题,也会导致数据库瞬间压力过大甚至崩溃,从而导致整个系统崩溃.今天就聊聊常见的redis缓存问题. 缓存击穿 …

了解HTTP代理服务器:优势、分类及应用实践

在我们日常的网络使用中&#xff0c;我们经常听到HTTP代理服务器这个术语。那么&#xff0c;HTTP代理服务器到底是什么&#xff1f;它有什么优势和分类&#xff1f;又如何应用于实践中呢&#xff1f;让我们一起来了解一下。 HTTP代理服务器是一种位于客户端和服务器之间的中间…