当前位置: 首页 > news >正文

Android开发-Android UI与布局

01  Android UI

1.1  UI

  • 用户界面(User Interface,简称 UI,亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介,它实现信息的内部形式与人类可以接受形式之间的转换。
  • 软件设计可分为两个部分:编码设计与UI设计

1.2  Android UI

  • Android应用界面包含用户可查看并与之交互的所有内容。Android 提供丰富多样的预置 UI ,例如结构化布局对象和 UI 控件,您可以利用这些组件为您的应用构建图形界面。Android 还提供其他界面模块,用于构建特殊界面,例如对话框、通知和菜单
  • Android UI 都是由布局和控件组成的

02   布局

布局(layout)可定义应用中的界面结构(例如 Activity 的界面结构)。布局中的所有元素均使用 View 和 ViewGroup 对象的层次结构进行构建。View 通常绘制用户可查看并进行交互的内容。然而, ViewGroup 是不可见容器,用于定义 View 和其他 ViewGroup 对象的布局结构

2.1  布局的结构

定义界面布局的视图层次结构图示:

View对象通常称为“微件”,可以是众多子类之一,例如Button或TextView。

ViewGroup对象通常称为“布局”,可以是提供其他布局结构的众多类型之一,例如LinearLayout或ConstraintLayout。

2.2  声明布局

XML 中声明界面元素,Android 提供对应 View 类及其子类的简明 XML 词汇,如用于微件和布局的词汇。

您也可使用 Android Studio 的 Layout Editor,并采用拖放界面来构建 XML 布局。

<?xml version="1.0" encoding="utf-8"?>
<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=".MainActivity"><TextViewandroid:layout_width="wrap_content" android:layout_height="wrap_content"android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

在运行时实例化布局元素。您的应用可通过编程创建 View 对象和 ViewGroup 对象(并操纵其属性)。

ConstraintLayout constraintLayout = new ConstraintLayout(this);
TextView view = new TextView(this);
view.setText("Hello World!");
constraintLayout.addView(view);

* 提示 : 使用 Layout Inspector 调试布局,可以查看通过代码创建的布局

  • 在连接的设备或模拟器上[运行您的应用]。
  • 依次点击 Tools > Layout Inspector。
  • 在显示的 Choose Process 对话框中,选择要检查的应用进程,然后点击 OK。

2.3  编写XML

  • 利用 Android 的 XML 词汇,按照在 HTML 中创建包含一系列嵌套元素的网页的相同方式快速设计UI 布局及其包含的屏幕元素
  • 每个布局文件都必须只包含一个根元素,并且该元素必须是视图对象或 ViewGroup 对象
  • 定义根元素后,可以子元素的形式添加其他布局对象或控件,从而逐步构建定义布局的视图层次结构
  • 在 XML 中声明布局后,以 .xml 扩展名将文件保存在Android项目的 res/layout/  目录中
<?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" ><TextView android:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello, I am a TextView" /><Button android:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello, I am a Button" />
</LinearLayout>
<LinearLayout>:视图容器标签
<TextView>:视图标签
<Button>:按钮标签

2.4  加载 XML 资源

当编译应用时,系统会将每个 XML 布局文件编译成View资源。在Activity.onCreate()回调内,通过调用 setContentView() ,并以R.layout.*layout_file_name*形式向应用代码传递布局资源的引用 ,加载应用代码中的布局资源。

    @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}

2.5  属性

每个 View 对象和 ViewGroup 对象均支持自己的各种 XML 属性 。某些属性是 View 对象的特有属性(例如,TextView 支持 textSize 属性),但可扩展此类的任一 View 对象也会继承这些属性。某些属性是所有 View 对象的共有属性,因为它们继承自 View 根类(例如id属性)。此外,其他属性被视为“布局参数”,即描述 View 对象特定布局方向的属性,如由该对象的父ViewGroup 对象定义的属性。

<TextViewandroid:id="@+id/tv" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="Hello World!" android:textSize="24sp"/>
<Buttonandroid:id="@+id/btn" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="按钮"/>
<TextView 文本视图android:id="@+id/tv" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="Hello World!"   展示的文本内容android:textSize="24sp"/>     文本的尺寸大小

2.6  ID


任何 View 对象均可拥有与之关联的整型 ID,用于在结构树中对 View 对象进行唯一标识。编译应用后,系统会以整型形式引用此 ID,但在布局 XML 文件中,系统通常会以字符串的形式在id属性中指定该 ID。这是所有 View 对象共有的 XML 属性(由view类定义),并且您会经常使用该属性。

  • XML 标记内部的 ID 语法是:
android:id="@+id/tv"
  • 字符串开头处的 @ 符号指示 XML 解析器应解析并展开 ID 字符串的其余部分,并将其标识为 ID 资源。加号 (+) 表示这是一个新的资源名称,必须创建该名称并将其添加到我们的资源(在R.java文件中)内。Android 框架还提供许多其他 ID 资源。引用 Android 资源 ID 时,不需要加号,但必须添加android软件包命名空间.
android:id="@android:id/empty"
添加android软件包命名空间后,我们现在将从android.R资源类而非本地资源类引用 ID.
tips: @+id @id区别:
其实@+id就是在R.java文件里新增一个id名称,如果之前已经存在相同的id名称,那么会覆盖之前的名称。而@id则是直接引用R.java文件的存在的id资源,如果不存在,会编译报错。
  • 注意: ID字符串名称,在同一布局中必须是唯一的,不能重名,不同布局中可以同名;
  • 通过ID值创建我们视图对象的实例
<TextViewandroid:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello World!"android:textSize="24sp"/>
TextView textView = (TextView) findViewById(R.id.tv);

2.7  布局参数LayoutParams

  • layout_***的布局属性
<TextViewandroid:layout_width="100dp" android:layout_height="200dp"android:layout_marginLeft="10dp" //左边距android:layout_marginTop="10dp" //上边距android:text="Hello World!" />
  • 布局参数作用是给我们的视图设定在布局中位置和大小
  • ViewGroup 类会实现一个扩展ViewGroup.LayoutParams的嵌套类,里面包含一些设置视图View的尺寸和位置的属性。
  • 视图层次结构图,包含每个视图关联的布局参数:

TextView tv = new TextView(this);
LinearLayout linearLayout = new LinearLayout(this);
LinearLayout.LayoutParams layoutParams =(LinearLayout.LayoutParams)tv.getLayoutParams();
layoutParams.leftMargin = 30; //左边距
layoutParams.topMargin = 30;//上边距
layoutParams.width = 100;//宽
layoutParams.height = 200;//高
tv.setLayoutParams(layoutParams);
linearLayout.addView(tv);
  •  一般而言,建议不要使用绝对单位(如像素)来指定布局宽度和高度。更好的方法是使用相对测量  单位(如与密度无关的像素单位(dp)wrap_contentmatch_parent),因为其有助于确保您的应用在各类尺寸的设备屏幕上正确显示。

wrap_content:指示您的视图将其大小调整为内容所需的尺寸。

match_parent:指示您的视图尽可能采用其父视图组所允许的最大尺寸。

2.8  布局位置

  • 视图可以通过调用getLeft()方法和getTop()方法来获取视图的坐标位置 ,也可以通过getWidth() getHeight() 获取视图的尺寸,这些方法返回的值是相对于其父视图的位置。
  • 位置和尺寸的单位是像素( px )
  • px dp 区 别
    • px 即像素,1px代表屏幕上一个物理的像素点;
    • 给视图设置px单位,不同分辨率下,尺寸不一样。
    • dp (dip) Density independent pixels ,设备无关像素。它与像素密度密切相关 ;dpi像素密度: 每英寸包含的像素数。
    • 假设有一部手机,屏幕的物理尺寸为1.5英寸x2英寸,屏幕分辨率为240x320,则我们    可以计算出在这部手机的屏幕上,每英寸包含的像素点的数量为240/1.5=160dpi(横向)或320/2=160dpi(纵向),160dpi就是这部手机的像素密度,像素密度的单位dpiDots Per Inch的缩写,即每英寸像素数量.

密度类型

代表的分辨率

(px)

屏幕密度

(dpi)

换算

(px/dp)

比例

低密度(ldpi)

240x320

120

1dp=0.75px

3

中密度(mdpi)

320x480

160

1dp=1px

4

高密度(hdpi)

480x800

240

1dp=1.5px

6

超高密度(xhdpi)

720x1280

320

1dp=2px

8

超超高密度

(xxhdpi)

1080x1920

480

1dp=3px

12

2.9 内边距和外边距

 

<TextViewandroid:id="@+id/tv" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="Hello World!" android:textSize="24sp"/>
<Buttonandroid:id="@+id/btn" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="按钮"/>
<?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:background="#ffc"android:orientation="vertical"><LinearLayoutandroid:layout_width="300dp"android:layout_height="300dp"android:layout_marginLeft="40dp"android:layout_marginTop="40dp"android:background="#DD001B"android:paddingLeft="40dp"android:paddingTop="40dp"><Viewandroid:layout_width="180dp"android:layout_height="180dp"android:background="#139948"/></LinearLayout></LinearLayout>

 


相关文章:

Android开发-Android UI与布局

01 Android UI 1.1 UI 用户界面(User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。 1.2 Andr…...

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…...

【11】核心易中期刊推荐——人工智能 | 图形图像处理

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

Spring 中的事件发布与监听

主要代码在org.springframework.context&#xff0c;org.springframework.context.event包中 事件发布与监听主要包含以下角色&#xff1a; 事件&#xff1a;ApplicationEvent事件监听器&#xff1a;ApplicationListener SmartApplicationListener GenericApplicationListene…...

c++ 一些常识 2

前言 今天主要讲类相关概念。 构造和析构函数是否可以抛出异常 在构造函数中抛出异常&#xff0c;控制权会转出构造函数之外&#xff0c;对象的析构函数不会被调用&#xff0c;造成内存泄漏。 如果析构函数中抛出异常&#xff0c;而且没有在当地捕捉&#xff0c;析构函数便执…...

用嘴写代码?继ChatGPT和NewBing之后,微软又开始整活了,Github Copilot X!

用嘴写代码&#xff1f;继ChatGPT和NewBing之后&#xff0c;微软又开始整活了&#xff0c;Github Copilot X&#xff01; AI盛行的时代来临了&#xff0c;在这段时间&#xff0c;除了爆火的GPT3.5后&#xff0c;OpenAI发布了GPT4版本&#xff0c;同时微软也在Bing上开始加入了A…...

3分钟阐述这些年我的 接口自动化测试 职业生涯经验分享

接口自动化测试学习教程地址&#xff1a;https://www.bilibili.com/video/BV1914y1F7Bv/ 你好&#xff0c;我是凡哥。 很高兴能够分享我的接口自动化测试经验和心得体会。在我目前的职业生涯中&#xff0c;接口自动化测试是我经常进行的一项任务。通过不断地学习和实践&#xf…...

十大Python可视化工具,太强了

今天介绍Python当中十大可视化工具&#xff0c;每一个都独具特色&#xff0c;惊艳一方。 Matplotlib Matplotlib 是 Python 的一个绘图库&#xff0c;可以绘制出高质量的折线图、散点图、柱状图、条形图等等。它也是许多其他可视化库的基础。 import matplotlib.pyplot as p…...

五.ElasticSearch的基础+实战

五.ElasticSearch的基础+实战 1.Elasticsearch的是什么? 2.Elasticsearch的作用是什么? 3.Elasticsearch的核心思想? 4.Elasticsearch启动与简单使用 5.kibana结合elasticsearch实现简单的增删改查 6.elasticsearch安装中文分词器 7.elasticsearch结合springboot开发…...

Oracle的学习心得和知识总结(十三)|Oracle数据库Real Application Testing之Database Reply实操(一)

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《Oracle Database SQL Language Reference》 2、参考书籍&#xff1a;《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Guid…...

CAD外部参照如何重新定位?CAD外部参照重定位步骤

CAD外部参照如何重新定位&#xff1f;这个问题并不算是一个常见的问题&#xff0c;但偶尔也会遇到&#xff0c;今天小编就来给大家简单介绍一下浩辰CAD软件中CAD外部参照重定位的操作步骤&#xff0c;一起来看看吧&#xff01; CAD外部参照重定位步骤&#xff1a; 浩辰CAD软件…...

11. C#高级进阶

一、C# 异常处理 在 C# 中&#xff0c;异常是在程序运行出错时引发的&#xff0c;所有异常都派生自 System.Exception 类。异常处理就是处理运行时错误的过程&#xff0c;通过异常处理可以使程序在发生错误时保持正常运行。 C# 中的异常处理基于四个关键字构建&#xff0c;分别…...

网络编程套接字( TCP协议通讯流程)

目录 1、绑定失败问题 2、TCP协议通讯流程 三次握手的过程 数据传输的过程 四次挥手的过程 TCP和UDP对比 1、绑定失败问题 当我们测试网络代码时&#xff0c;先将服务端绑定8080端口运行&#xff0c;然后运行客户端&#xff0c;并让客户端连接当前服务器&#xff1a; 当有客户…...

WPF毛笔字实现过程

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

MHA实现mysql数据库高可用

目录 MHA原理 MHA工具包 MHA实现mysql高可用实战 MHA原理 ①MHA利用 SELECT 1 As Value 指令判断master服务器的健康性,一旦master 宕机,MHA 从宕机崩溃的master保存二进制日志事件&#xff08;binlog events&#xff09; ②识别含有最新更新的slave ③应用差异的中继日志&…...

leetcode每日一题:55. 跳跃游戏

系列&#xff1a;贪心算法 语言&#xff1a;java 题目来源&#xff1a;Leetcode55. 跳跃游戏 题目 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1: 输…...

【C++】map 和 set

文章目录一、关联式容器与键值对1、关联式容器2、键值对 pair3、树形结构的关联式容器二、set1、set 的介绍2、set 的使用三、multiset四、map1、map 的介绍2、map 的使用五、multimap一、关联式容器与键值对 1、关联式容器 在C初阶的时候&#xff0c;我们已经接触了 STL 中的…...

基于SpringBoot的酒店管理系统

系统环境 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/i…...

JAVA框架知识整理

框架知识整理 SpringBoot、SpringMVC、Spring的区别和他们的作用&#xff1f; SpringBoot是一个微服务框架&#xff0c;其简化了Spring应用的创建、运行、测试、部署。使开发人员无需过多的关注XML配置。里面整合了许多框架例如SpringMVC、Spring Security和Spring Data JPA。…...

运算放大器:电压比较器

目录一、单限电压比较器二、滞回电压比较器三、窗口电压比较器最近在学习电机控制&#xff0c;遇到了与运算放大电路相关的知识&#xff0c;然而太久没有接触模拟电路&#xff0c;对该知识已经淡忘了&#xff0c;及时温故而知新&#xff0c;做好笔记&#xff0c;若有错误、不足…...

Linux的基础知识

根目录和家目录根目录&#xff1a;是Linux中最底层的目录&#xff0c;用"/"表示家目录&#xff1a;当前用户所在的路径&#xff0c;用“~”表示&#xff0c;root用户的家目录和普通用户的家目录不一样&#xff0c;普通用户的家目录在/home路径下&#xff0c;每一个用…...

【JavaEE】 IntelliJ IDEA 2022.2最新版Tomcat导入依赖详细教程全解及创建第一个Servlet程序

目录 一、软件资源 二、放置settings.xml文件 三、创建项目 四、引入依赖 ​五、创建目录 六、编写代码 写在前面&#xff1a;☞What is Servlet? Servlet其实是一种实现动态页面的技术。是一组由Tomcat提供给程序员的API&#xff08;应用程序编程接口&#xff09;…...

常见的卷积神经网络结构——分类、检测和分割

本文持续更新~~ 本文整理了近些年来常见的卷积神经网络结构&#xff0c;涵盖了计算机视觉领域的几大基本任务&#xff1a;分类任务、检测任务和分割任务。对于较复杂的网络&#xff0c;本文只会记录其中的核心模块以及重要的网络设计思想&#xff0c;并不会记录完整的网络结构。…...

20230323英语学习

Why Can You “Hear the Ocean” in Seashells? 为啥能在贝壳里“听见海的声音”&#xff1f; We’re told a number of stories as kids. One of the more harmless of these little lies is the one about seashells.You know the one: hold up a seashell to your ear, an…...

【粉丝投稿】上海某大厂的面试题,岗位是测开(25K*16)

简单介绍一句&#xff0c;大专出身&#xff0c;三年经验。跳了四次槽&#xff0c;面试了无数次&#xff0c;现在把自己的面试经验整理出来分享给大家&#xff0c;堪称必杀技&#xff01; 1&#xff0c;一切从实际出发&#xff0c;对实际工作进行适当修饰 2&#xff0c;不会的简…...

shell简单使用介绍

脚本的基本元素声明&#xff0c;在解释并执行当前脚本文件中的语句之前&#xff0c;需要声明使用的命令解释器#一般写的解释器为 #!/bin/bash这里的#不再是注释了&#xff0c;而是必要的声明命令&#xff0c;也就是需要执行的语句注释&#xff0c;对代码进行解释说明分为单行注…...

RK3568平台开发系列讲解(调试篇)内核函数调用堆栈打印方法汇总

🚀返回专栏总目录 文章目录 一、dump_stack 函数二、WARN_ON(condition)函数三、BUG_ON (condition)函数四、panic (fmt...)函数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将对驱动调试方法进行汇总学习。 一、dump_stack 函数 dump_stack 作用:打印内核调…...

一次内存泄露排查

前因&#xff1a; 因为测试 长时间压测导致 接口反应越来越慢&#xff0c;甚至 导致服务器 崩溃 排查过程 1、top 查看是 哪个进程 占用 内存过高 2、根据 进程 id 去查找 具体是哪个 程序的问题 ps -ef| grep 41356 可以看到 具体的 容器位置 排查该进程 对象存活 状态…...

「Mac安装ps」Adobo Photoshop 2023 下载安装详情教程,支持 AI 插件的 24 版 Photoshop

前言 Adobo Photoshop 2023 已推出&#xff0c;由于目前AI人工智能技术火爆&#xff0c;而很多的 AI 插件最低也需要24版的 photoshop &#xff0c;所以这里我遍搜集并整理了此新版本的 photoshop 安装使用教程&#xff0c;后续也将提供 AI 插件的下载安装教程 安装文件下载 …...

Redis单线程还是多线程?IO多路复用原理

目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程&#xff1f;三、Redis6.0引入多线程四、Redis主线程和IO线程是如何完成请求的&#xff1f;1、服务端和客户端建立socket连接2、IO线程读取并解析请求3、主线程执行请求命令4、IO线程会写回socket和主线程清…...

临湘市建设局网站/考研培训班集训营

微信小程序官网&#xff1a; https://mp.weixin.qq.com/cgi-bin/wx 小程序如何唤起APP?小程序支持跳转APP了&#xff0c;怎样实现双赢&#xff1f; http://www.apppark.cn/t-941.html 有了小程序是不是可以卸载所有的APP了&#xff1f; http://www.sohu.com/a/200685713_…...

深圳高端做网站公司/百度小说搜索热度排行榜

首先&#xff1a; filter方法的使用可以参考&#xff1a; https://blog.csdn.net/weixin_41615439/article/details/108661807 使用filter操作对象数组&#xff0c;可以减少不必要的请求&#xff1b;如果不是对象数组&#xff0c;那filter方法是没有改变原数组的。 1、首先&…...

wordpress 图片插件/seo是啥

history对象保存用户上网的历史记录&#xff0c;从窗口被打开的那一刻算起。历史记录对象是窗口对象下的一个子对象&#xff0c;它实际上是一个对象数组&#xff0c;包含了一系列的用户访问过的URL地址。保存着用户的上网历史记录&#xff0c;用于浏览器工具栏中的"Back t…...

wordpress 按时间排序/微信小程序免费制作平台

开发Android应用过程一般分为三步&#xff1a; 1、创建一个Android工程&#xff1b; 2、在xml布局文件中定义应用所包含的控件&#xff1b; 3、在Java代码中实现业务逻辑。 此文就介绍第一部分&#xff0c;创建一个Android工程&#xff0c;具体步骤如下&#xff1a; 1、打开ecl…...

wordpress 媒体库 链接/市场营销实务

系统消息和通知 阻塞队列 BlockingQueue时一个接口&#xff0c;又许多实现类 Kafka入门 高吞吐量&#xff1a;Kafka是硬盘顺序读取&#xff1a;硬盘顺序读取高于内存的随机读取。 高可靠性&#xff1a;分布式的集群 高扩展性&#xff1a;加集群很方便 Broker&#xff1a;K…...

创建私人网站/石家庄百度seo代理

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…...