android自动适应屏幕.一、细说layout_weight

Android自适应布局技巧
本文介绍了一种在Android开发中实现多屏幕自适应的有效方法,通过使用特定的样式和属性组合,如layout_width和layout_height的0px设置及layout_weight属性,确保不同尺寸设备上的界面元素按预期比例显示。

目前最为推荐的Android多屏幕自适应解决方案。
该属性的作用是决定控件在其父布局中的显示权重,一般用于线性布局中。其值越小,则对应的layout_width或layout_height的优先级就越高,一般横向布局中,决定的是 layout_width 的优先级;纵向布局中,决定的是 layout_height 的优先级。
传统的layout_weight使用方法是将当前控件的layout_widthlayout_height都设置成fill_parent,这样就可以把控件的显示比例完全交给layout_weight;这样使用的话,就出现了layout_weight越小,显示比例越大的情况。不过对于2个控件还好,如果控件过多,且显示比例也不相同的时候,控制起来就比较麻烦了,毕竟反比不是那么好确定的。
于是就有了现在最为流行的 0px设值法。看似让人难以理解的layout_height=0px的写法,结合layout_weight,却可以使控件成正比例显示,轻松解决了当前Android开发最为头疼的碎片化问题之一。
先看下面的stylesstyle_layout.xml

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version= "1.0" encoding= "utf-8" ?>
<resources>
<!-- 全屏幕拉伸-->
<style name= "layout_full" >
<item name= "android:layout_width" >fill_parent</item>
<item name= "android:layout_height" >fill_parent</item>
</style>
<!-- 固定自身大小-->
<style name= "layout_wrap" >
<item name= "android:layout_width" >wrap_content</item>
<item name= "android:layout_height" >wrap_content</item>
</style>
<!-- 横向分布-->
<style name= "layout_horizontal" parent= "layout_full" >
<item name= "android:layout_width" >0px</item>
</style>
<!-- 纵向分布-->
<style name= "layout_vertical" parent= "layout_full" >
<item name= "android:layout_height" >0px</item>
</style>
</resources>

可以看到,layout_widthlayout_height两个属性被我封装成了4style
根据实际布局情况,选用当中的一种,不需要自己设置,看过我前一个ActivityGroupDemo的同学应该非常熟悉了
然后我的Demo的布局如下(weight_layout.xml

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?xml version= "1.0" encoding= "utf-8" ?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
style= "@style/layout_full"
android:orientation= "vertical" >
<LinearLayout
style= "@style/layout_vertical"
android:layout_weight= "1"
android:orientation= "horizontal" >
<View
style= "@style/layout_horizontal"
android:background= "#aa0000"
android:layout_weight= "1" />
<View
style= "@style/layout_horizontal"
android:background= "#00aa00"
android:layout_weight= "4" />
<View
style= "@style/layout_horizontal"
android:background= "#0000aa"
android:layout_weight= "3" />
<View
style= "@style/layout_horizontal"
android:background= "#aaaaaa"
android:layout_weight= "2" />
</LinearLayout>
<LinearLayout
style= "@style/layout_vertical"
android:layout_weight= "2"
android:orientation= "vertical" >
<View
style= "@style/layout_vertical"
android:background= "#ffffff"
android:layout_weight= "4" />
<View
style= "@style/layout_vertical"
android:background= "#aa0000"
android:layout_weight= "3" />
<View
style= "@style/layout_vertical"
android:background= "#00aa00"
android:layout_weight= "2" />
<View
style= "@style/layout_vertical"
android:background= "#0000aa"
android:layout_weight= "1" />
</LinearLayout>
</LinearLayout>

整个界面布局看起来非常直观,只是嵌套的逻辑要自己理下。显示效果如下图,其中左面一个是 480x800 的界面,右面的是 320x480 的界面(后面的图也如此),可以看出显示比例和代码中完全一致,我就不多说了,大家对照下就能看出来了。
1.png
下面maixcam的代码逻辑是什么? 细说 from maix import image, display, app, time, camera import cv2 import os 创建保存图片的目录 save_dir = ‘/boot/shengwu’ if not os.path.exists(save_dir): os.makedirs(save_dir) disp = display.Display() cam = camera.Camera(320, 240, image.Format.FMT_BGR888) 初始化圆形跟踪参数 last_circles = None circle_count = 0 last_save_time = 0 save_interval = 5000 # 保存间隔时间,单位为毫秒 while not app.need_exit(): img = cam.read() # convert maix.image.Image object to numpy.ndarray object t = time.ticks_ms() img_cv = image.image2cv(img, ensure_bgr=False, copy=False) print("time: ", time.ticks_ms() - t) # 创建用于显示的图像副本 img_display = img_cv.copy() # 圆形检测 gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY) gray = cv2.medianBlur(gray, 5) # 使用霍夫圆变换检测圆形 circles = cv2.HoughCircles( gray, # 输入图像 cv2.HOUGH_GRADIENT, # 检测方法 1, # 累加器图像的分辨率与输入图像之比 30, # 检测到的圆的圆心之间的最小距离 param1=100, # Canny边缘检测的高阈值 param2=30, # 累加器阈值,值越小,检测到的圆越多 minRadius=10, # 最小圆半径 maxRadius=100 # 最大圆半径 ) current_time = time.ticks_ms() time_since_last_save = current_time - last_save_time # 如果检测到圆形 if circles is not None: circles = circles[0, :].astype("int") last_circles = circles circle_count += 1 # 保存未绘制标记的原始图像 if time_since_last_save >= save_interval: # 获取当前时间并格式化为时间戳字符串 now = time.localtime() # 正确访问DateTime对象的属性 year_short = str(now.year)[-2:] # 取年份后两位 month = str(now.month).zfill(2) # 月份补零 day = str(now.day).zfill(2) # 日期补零 hour = str(now.hour).zfill(2) # 小时补零 minute = str(now.minute).zfill(2) # 分钟补零 timestamp = f"{year_short}_{month}{day}_{hour}{minute}" img_path = os.path.join(save_dir, f"{timestamp}.jpg") cv2.imwrite(img_path, img_cv) # 保存原始图像 print(f"保存图片: {img_path}") last_save_time = current_time # 绘制检测到的圆形 for (x, y, r) in circles: cv2.circle(img_display, (x, y), r, (0, 255, 0), 2) cv2.circle(img_display, (x, y), 2, (0, 0, 255), 3) cv2.putText(img_display, f"({x}, {y})", (x - 20, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) # 如果之前检测到过圆形但当前帧没有检测到 elif last_circles is not None: for (x, y, r) in last_circles: overlay = img_display.copy() cv2.circle(overlay, (x, y), r, (0, 255, 255), 2) cv2.addWeighted(overlay, 0.5, img_display, 0.5, 0, img_display) # 在画面上显示剩余保存时间 remaining_time = max(0, (save_interval - time_since_last_save) // 1000) cv2.putText(img_display, f"下次保存: {remaining_time}秒", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) # show by maix.display img_show = image.cv2image(img_display, bgr=True, copy=False) disp.show(img_show)
最新发布
07-09
<think>我们分析下这段代码的逻辑。这段代码是在MaixCam(种基于Linux的AIoT开发板)上运行的,主要功能是使用摄像头捕获图像,检测图像中的圆形,并定期保存原始图像(不包含绘制的标记)到指定目录。 代码逻辑分解: 1. **导入必要的库**: - `maix`中的`image`, `display`, `app`, `time`, `camera`:用于摄像头控制、图像显示、时间获取和应用程序控制。 - `cv2`:OpenCV库,用于图像处理(这里用于圆形检测)。 - `os`:用于文件和目录操作。 2. **创建保存图片的目录**: - 指定保存目录为`/boot/shengwu`(注意:代码中使用了中文引号,实际应该是英文引号,这里可能是复制粘贴的问题,需要修正为英文引号)。 - 如果目录不存在,则创建它。 3. **初始化显示和摄像头**: - `display.Display()`:初始化显示设备。 - `camera.Camera(320, 240, image.Format.FMT_BGR888)`:初始化摄像头,分辨率为320x240,图像格式为BGR888。 4. **初始化变量**: - `last_circles`:用于存储上帧检测到的圆形。 - `circle_count`:计数检测到圆形的帧数(但代码中并未使用这个计数做其他操作,可能是预留的)。 - `last_save_time`:上次保存图片的时间(毫秒)。 - `save_interval`:保存图片的时间间隔(5000毫秒,即5秒)。 5. **主循环**: - 循环直到应用程序退出(`app.need_exit()`返回`True`)。 - 读取帧图像(`cam.read()`)。 - 将`maix.image.Image`对象转换为OpenCV的`numpy.ndarray`对象(`image.image2cv`)。这里注意参数`ensure_bgr=False`和`copy=False`,表示不确保BGR格式(因为输入就是BGR888)且不复制(为了效率)。 - 创建个用于显示的图像副本(`img_display`),这样我们可以在副本上绘制而不影响原始图像。 6. **圆形检测**: - 将图像转换为灰度图(`cv2.cvtColor`)。 - 使用中值滤波去噪(`cv2.medianBlur`)。 - 使用霍夫圆变换(`cv2.HoughCircles`)检测圆形,参数设置包括最小圆心距、Canny高阈值、累加器阈值、最小半径和最大半径。 7. **处理检测结果**: - 如果检测到圆形(`circles`不为`None`): - 提取圆形参数(圆心坐标和半径)。 - 更新`last_circles`为当前检测到的圆形。 - `circle_count`加1。 - 检查自上次保存以来是否已经过了`save_interval`(5秒)。如果是,则保存原始图像(`img_cv`)到文件。文件名使用当前时间(年两位+月日+小时分钟)生成,保存在之前创建的目录中。同时更新`last_save_time`。 - 在显示图像副本上绘制检测到的圆形(绿色圆和红色圆心)并标注圆心坐标。 - 如果当前帧没有检测到圆形,但之前检测到过(`last_circles`不为`None`): - 在显示图像副本上绘制上次检测到的圆形,但使用半透明的黄色(通过`cv2.addWeighted`实现半透明效果)。 8. **显示剩余保存时间**: - 计算距离下次保存的剩余时间(秒),并显示在图像左上角。 9. **显示图像**: - 将处理后的显示图像副本(`img_display`)转换回`maix.image.Image`格式(`image.cv2image`),然后通过`display`显示。 **注意**:代码中有个小错误,保存图片时使用的是原始图像`img_cv`(未绘制任何标记),而显示的是绘制了圆形的`img_display`。这样保存的图片是干净的原始图像。 **修正**:代码中创建目录的语句使用了中文引号,应该改为英文引号: ```python save_dir = '/boot/shengwu' ``` 另外,注意`cv2.HoughCircles`返回的圆形是浮点数,需要转换为整数(代码中已经做了`astype("int")`)。 下面给出修正后的完整代码(注意:只修正了引号,其他逻辑不变):</think>这段代码是用于在 MaixCam 设备上实现圆形检测并定期保存原始图像的程序。下面是详细的逻辑分析: ### 代码逻辑详解 1. **初始化设置** ```python # 创建保存图片的目录 save_dir = '/boot/shengwu' # 注意:修正了原始代码中的中文引号问题 if not os.path.exists(save_dir): os.makedirs(save_dir) # 初始化显示和摄像头 disp = display.Display() cam = camera.Camera(320, 240, image.Format.FMT_BGR888) # 初始化圆形跟踪参数 last_circles = None # 存储上次检测到的圆形 circle_count = 0 # 圆形检测计数 last_save_time = 0 # 上次保存时间 save_interval = 5000 # 保存间隔(5秒) ``` 2. **主循环处理** ```python while not app.need_exit(): img = cam.read() # 读取摄像头帧 # 转换为OpenCV格式 img_cv = image.image2cv(img, ensure_bgr=False, copy=False) img_display = img_cv.copy() # 创建用于显示的副本 ``` 3. **圆形检测** ```python # 预处理图像 gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY) gray = cv2.medianBlur(gray, 5) # 中值滤波去噪 # 霍夫圆检测 circles = cv2.HoughCircles( gray, # 输入图像 cv2.HOUGH_GRADIENT, # 检测方法 1, # 分辨率比例 30, # 圆心最小间距 param1=100, # Canny边缘检测阈值 param2=30, # 累加器阈值(值越小检测越多) minRadius=10, # 最小半径 maxRadius=100 # 最大半径 ) ``` 4. **检测结果处理** ```python current_time = time.ticks_ms() time_since_last_save = current_time - last_save_time if circles is not None: # 检测到圆形 circles = circles[0, :].astype("int") last_circles = circles circle_count += 1 # 定期保存原始图像 if time_since_last_save >= save_interval: # 生成时间戳文件名 now = time.localtime() year_short = str(now.year)[-2:] month = str(now.month).zfill(2) day = str(now.day).zfill(2) hour = str(now.hour).zfill(2) minute = str(now.minute).zfill(2) timestamp = f"{year_short}_{month}{day}_{hour}{minute}" # 保存原始图像(不带标记) img_path = os.path.join(save_dir, f"{timestamp}.jpg") cv2.imwrite(img_path, img_cv) last_save_time = current_time # 在显示图像上绘制圆形 for (x, y, r) in circles: cv2.circle(img_display, (x, y), r, (0, 255, 0), 2) # 绿色外圈 cv2.circle(img_display, (x, y), 2, (0, 0, 255), 3) # 红色圆心 cv2.putText(img_display, f"({x}, {y})", (x - 20, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) elif last_circles is not None: # 未检测到但之前有记录 # 绘制半透明的历史圆形 for (x, y, r) in last_circles: overlay = img_display.copy() cv2.circle(overlay, (x, y), r, (0, 255, 255), 2) cv2.addWeighted(overlay, 0.5, img_display, 0.5, 0, img_display) ``` 5. **显示处理结果** ```python # 显示剩余保存时间 remaining_time = max(0, (save_interval - time_since_last_save) // 1000) cv2.putText(img_display, f"下次保存: {remaining_time}秒", (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1) # 显示图像 img_show = image.cv2image(img_display, bgr=True, copy=False) disp.show(img_show) ``` ### 关键功能总结 1. **圆形检测** - 使用霍夫圆变换检测图像中的圆形 - 实时绘制检测到的圆形位置和半径 - 当检测失败时显示上次检测结果(半透明黄色) 2. **图像保存** - 每5秒保存次原始图像(不带标记) - 文件名格式:YY_MMDD_HHMM.jpg(如23_1201_1430.jpg) - 保存到`/boot/shengwu`目录 3. **用户界面** - 实时显示检测到的圆形位置坐标 - 显示距离下次保存的倒计时 - 绿色实心圆:当前检测到的圆形 - 黄色半透明圆:历史检测到的圆形 4. **异常处理** - 自动创建保存目录(如果不存在) - 处理检测结果丢失的情况(显示历史数据) ### 工作流程图 ``` 摄像头捕获 → 图像预处理 → 圆形检测 → ├→ 检测成功:绘制圆形+保存原始图(定时) └→ 检测失败:显示历史圆形 显示处理结果 + 保存倒计时 ``` ### 修正说明 原始代码中存在中文引号问题(`‘/boot/shengwu’`),我已修正为英文引号(`'/boot/shengwu'`),这是Python语法要求的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值