iOS 练习项目 Landmarks (四):添加 AutoLayout 约束

iOS 练习项目 Landmarks (四):添加 AutoLayout 约束

  • iOS 练习项目 Landmarks (四):添加 AutoLayout 约束
    • 新增 topLabel
    • 图片视图圆形裁切+阴影
    • 使用 AutoLayout 为详情页的组件添加约束
    • DetailViewControllerDelegate
    • 为 PlaceCell 添加 AutoLayout 约束

iOS 练习项目 Landmarks (四):添加 AutoLayout 约束

新增 topLabel

与参考视频对比,返回标签的右边还要有一个显示景点名的标题,在详情页新增一个居中的 UILabel 来显示,命名为 topLabel。

图片视图圆形裁切+阴影

要使得图片展示为一个圆形,先设置一个正方形的 pictureView,再设置它的 layer.cornerRadius 为边长的一半,masksToBounds 是 layer 的属性,含义是子视图是否裁剪图层边界,设置为 YES 后,imageView 超出半径的部分就被裁减掉,这样就剩下一个圆形。

在圆形外设置一个 4px 的白色 border,就完成了边界的设置。

然后设置边界外的阴影,通过设置 layer.shadowOffset、layer.shadowRedius、layer.shadowPath、layer.shadowColor、layer.shadowOpacity 等属性,但是没有效果,因为 masksToBounds = true 会把设置的阴影裁剪掉。一种添加阴影的方法是在 pictureView 外套一层 shadowView,shadowView 的 frame 大小和 pictureView 相同,在 shadowView 上设置阴影效果,再让 picture View 作为 shadowView 的子视图。

    CGRect pictureFrame = CGRectMake(0, 0, 250, 250);// 创建并设置 pictureViewself.pictureView = [[UIImageView alloc] initWithFrame:pictureFrame];[self.pictureView setImage:[self.place picture]];self.pictureView.layer.cornerRadius = 125.0;self.pictureView.layer.borderWidth = 4.0;self.pictureView.layer.borderColor = [UIColor whiteColor].CGColor;// self.pictureView.contentMode = UIViewContentModeScaleAspectFit;self.pictureView.translatesAutoresizingMaskIntoConstraints = NO;// 在 pictureView 上直接设置阴影,会因为 masksToBounds = true 而被裁减掉self.pictureView.layer.masksToBounds = YES;// 在 pictureView 外套一层 shadowViewUIView *shadowView = [[UIView alloc] initWithFrame:self.pictureView.frame];shadowView.layer.shadowColor = [UIColor grayColor].CGColor;shadowView.layer.shadowOffset = CGSizeMake(0, 0);shadowView.layer.shadowOpacity = 1;shadowView.layer.shadowRadius = 9.0;shadowView.layer.cornerRadius = 9.0;[shadowView addSubview:self.pictureView];...[self.view addSubview:shadowView];
  • clipToBounds 是 view 的属性,含义是子视图只展示父视图边界内的内容,边界外会被裁减掉,默认为 NO。
  • masksToBounds 是 layer 的属性,含义是子视图是否裁剪图层边界,默认为 NO。

使用 AutoLayout 为详情页的组件添加约束

UIView 有一个属性:translatesAutoresizingMaskIntoConstraints,字面意思是把 autoresizingMask 转换为 Constraints,实际意思是把 frame ,bouds,center 方式布局的视图自动转化为约束形式,此时该视图上约束已经足够,不需要手动去添加别的约束。

  • 用代码创建的所有view , translatesAutoresizingMaskIntoConstraints 默认是 YES
  • 用 IB 创建的所有 view ,translatesAutoresizingMaskIntoConstraints 默认是 NO(autoresize 布局为 YES , autolayout 布局为 NO)。

如果我们要给视图添加自己创建的约束,会和上述约束冲突,所以使用 AutoLayout 前需要将视图的 translatesAutoresizingMaskIntoConstraints 属性设置为 NO。

接下来就是添加约束了:

		/* 添加约束 */// topLabel 的上边缘距离 view 的上边缘有 50px,且居中显示[NSLayoutConstraint activateConstraints:@[[self.topLabel.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:50],[self.topLabel.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], // 设置视图位于 X 轴居中[self.topLabel.heightAnchor constraintEqualToConstant:50] // 设置视图的高度为 50 点]];// mapView 的上边缘位于 topLabel 的下边缘NSLayoutConstraint *mapTopAttachToTopButtom = [NSLayoutConstraint constraintWithItem:self.mapView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLabel attribute:NSLayoutAttributeBottom multiplier:1 constant:0];[self.view addConstraint:mapTopAttachToTopButtom];[NSLayoutConstraint activateConstraints:@[[self.mapView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], // 设置地图视图位于 X 轴居中// [self.mapView.topAnchor constraintEqualToAnchor:self.topLabel.bottomAnchor],// [self.mapView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],// [self.mapView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],[self.mapView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor],[self.mapView.heightAnchor constraintEqualToConstant:290] // 设置地图视图的高度为 290px]];// pictureView 的中心位于 mapView 的下边缘NSLayoutConstraint *pictureCenterYAttachToMapButtom = [NSLayoutConstraint constraintWithItem:self.pictureView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.mapView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];[self.view addConstraint:pictureCenterYAttachToMapButtom];// pictureView 的宽高为 250px,且 X 轴居中[NSLayoutConstraint activateConstraints:@[[self.pictureView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor], // 设置图片视图位于 X 轴居中// [self.pictureView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor], // 设置图片视图位于 Y 轴居中[self.pictureView.widthAnchor constraintEqualToConstant:250], // 设置图片视图的宽度为 250px[self.pictureView.heightAnchor constraintEqualToConstant:250] // 设置图片视图的高度为 250px]];// sightLabel 位于 pictureView 下方 30px 处,距离屏幕左边界 20px[NSLayoutConstraint activateConstraints:@[[self.sightLabel.topAnchor constraintEqualToAnchor:self.pictureView.bottomAnchor constant:30],[self.sightLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],[self.sightLabel.heightAnchor constraintEqualToConstant:80]]];// starButton 位于 sightLabel 右侧,距离 4px[NSLayoutConstraint activateConstraints:@[[self.starButton.leadingAnchor constraintEqualToAnchor:self.sightLabel.trailingAnchor constant:4],[self.starButton.topAnchor constraintEqualToAnchor:self.sightLabel.topAnchor],[self.starButton.bottomAnchor constraintEqualToAnchor:self.sightLabel.bottomAnchor],[self.starButton.widthAnchor constraintEqualToConstant:25],[self.starButton.heightAnchor constraintEqualToConstant:25]]];// scenicAreaLabel 位于 sightLabel 下方,距离 15px[NSLayoutConstraint activateConstraints:@[[self.scenicAreaLabel.topAnchor constraintEqualToAnchor:self.sightLabel.bottomAnchor constant:15],[self.scenicAreaLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20],[self.scenicAreaLabel.heightAnchor constraintEqualToConstant:20]]];// stateLabel 与 scenicAreaLabel 水平,其右边界距离屏幕右边界 20px[NSLayoutConstraint activateConstraints:@[[self.stateLabel.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20],[self.stateLabel.topAnchor constraintEqualToAnchor:self.scenicAreaLabel.topAnchor],[self.stateLabel.bottomAnchor constraintEqualToAnchor:self.scenicAreaLabel.bottomAnchor],[self.stateLabel.heightAnchor constraintEqualToConstant:20]]];

DetailViewControllerDelegate

详情页的 starButton 也要能修改数据源,所以在 DetailViewController 里声明一个 DetailViewControllerDelegate 协议。

@protocol DetailViewControllerDelegate <NSObject>@optional- (void)detailViewController:(DetailViewController *)detailViewController goBackWithFavorite:(BOOL)favorite atIndex:(NSInteger)index;@end@interface DetailViewController : UIViewController@property (nonatomic, weak) id <DetailViewControllerDelegate> detailViewControllerDelegate;...@end

里面有一个可选方法,作用是将 favorite 从详情页传回主页,根据 index 修改数据源对应下标的 Place 对象的 favorite 属性。

在 ViewController 引入这个协议,在 tableView:didSelectRowAtIndexPath: 方法中,我们创建了 DetailViewController 对象,之后要设置代理,别忘了设置 index 属性:

// 设置代理,并且遵守 DetailViewControllerDelegate
detailViewController.detailViewControllerDelegate = self;
// 别忘了设置 index 属性
[detailViewController setIndex:indexPath.row];

并且实现协议的方法:

# pragma mark - DtailViewControllerDelegate Method- (void)detailViewController:(DetailViewController *)detailViewController goBackWithFavorite:(BOOL)favorite atIndex:(NSInteger)index
{// 修改数据源对应的对象[self.places[index] setFavorite:favorite];// TableView 重新加载被修改了的那一行[placeTable reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationNone];// [self.placeTable reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationNone];
}

为详情页的starButton的点击事件添加一个目标-动作对,点击按钮,将starButton.selected保存到favorite,再通知代理执行协议方法:

- (void)starButtonClicked:(UIButton *)sender
{sender.selected = !sender.selected;// [place setFavorite:sender.selected];self.favorite = sender.selected;// 首先判断代理人是否存在并且是否遵守协议并且实现了协议方法if (_detailViewControllerDelegate && [_detailViewControllerDelegate respondsToSelector:@selector(detailViewController:goBackWithFavorite:atIndex:)]){// 如果满足判断条件,则让代理执行协议方法,此处让代理人执行协议方法,在代理人那个控制器中的协议方法会被执行[_detailViewControllerDelegate detailViewController:self goBackWithFavorite:self.favorite atIndex:self.index];}
}

为 PlaceCell 添加 AutoLayout 约束

之前提到过:在自己实现的PlaceCell中,目前只有imageView的上面空出了10px,其实下面也要空出距离,实现imageView和contentView的上下都有空位的效果。现在通过 AutoLayout 约束,使得 imageView 的上下分别距离 contentView 5px,就可以实现这个效果,再设置 textLabel 和 starButton 位于 contentView 的 Y 轴居中。

    // 添加约束[NSLayoutConstraint activateConstraints:@[[self.imageView.widthAnchor constraintEqualToConstant:50],[self.imageView.heightAnchor constraintEqualToConstant:50],[self.imageView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:20],[self.imageView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:5],[self.imageView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-5],[self.textLabel.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor],[self.textLabel.leadingAnchor constraintEqualToAnchor:self.imageView.trailingAnchor constant:10],[self.starButton.centerYAnchor constraintEqualToAnchor:self.contentView.centerYAnchor], // 设置图片视图位于 Y 轴居中[self.starButton.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-10],[self.starButton.widthAnchor constraintEqualToConstant:25],[self.starButton.heightAnchor constraintEqualToConstant:25]]];

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

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

相关文章

如何在 Logback 和 Log4j 中获取日志:一个开发者指南

日志记录是软件开发中的关键实践&#xff0c;它帮助我们监控应用程序的行为&#xff0c;定位问题并优化性能。在 Java 生态系统中&#xff0c;Logback 和 Log4j 是两个广泛使用的日志框架&#xff0c;它们都基于 SLF4J API 提供日志服务。本文将指导你如何在这两个框架中获取日…

7-490 将字符串“software“赋给一个字符指针,并从第一个字母开始间隔地输出该串(简单字符串)

编程将字符串"software"赋给一个字符指针 然后从第一个字母开始间隔地输出该串 请用指针法完成。 输入样例: 在这里给出一组输入。例如&#xff1a; 无输入输出样例: 在这里给出相应的输出。例如&#xff1a; sfwr #include <stdio.h> #include <stri…

Linux环境下快速部署Spring Boot应用:高效命令组合实践

概要&#xff1a; 本文旨在介绍一种高效的Linux命令组合&#xff0c;用于简化Spring Boot项目的部署与管理流程。通过结合使用nohup、java -jar、输出重定向以及进程管理命令&#xff0c;我们能够实现Spring Boot应用的快速后台启动及便捷的进程控制&#xff0c;尤其适合于自动…

什么是 JVM( Java 虚拟机),它在 Java 程序执行中扮演什么角色?

JVM&#xff0c;全称Java Virtual Machine&#xff0c;中文译作“Java虚拟机”&#xff0c;它是运行Java程序的软件环境&#xff0c;也是Java语言的核心部分之一。 想象一下&#xff0c;如果你是一位环球旅行家&#xff0c;每到一个新的国家&#xff0c;都需要学习当地的语言才…

【Linux】初识操作系统

一、冯•诺依曼体系结构 在学习操作系统之前&#xff0c;我们先来认识一下冯•诺依曼体系结构&#xff0c;我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 截至目前&#xff0c;我们所认识的计算机&am…

神经网络训练(一):基于残差连接的图片分类网络(ResNet18)

目录 一、简介:二、图片分类网络1.记载训练数据(torch自带的cifa10数据集)2.数据增强3.模型构建4.模型训练三、完整源码及文档一、简介: 基于残差连接的图片分类网络,本网络使用ResNet18作为基础模块,根据cifa10的特点进行改进网络,使用交叉熵损失函数和SGD优化器。本网…

使用pyqt5编写一个七彩时钟

使用pyqt5编写一个七彩时钟 效果代码解析定义 RainbowClockWindow 类初始化用户界面显示时间方法 完整代码 在这篇博客中&#xff0c;我们将使用 PyQt5 创建一个简单的七彩数字时钟。 效果 代码解析 定义 RainbowClockWindow 类 class RainbowClockWindow(QMainWindow):def _…

【TB作品】温湿度监控系统设计,ATMEGA16单片机,Proteus仿真

题2:温湿度监控系统设计 功能要求: 1)开机显示时间(小时、分)、时分可修改; 2)用两个滑动变阻器分别模拟温度传感器(测量范 围0-100度)与湿度传感器(0-100%),通过按键 可以在数码管切换显示当前温度值、湿度值; 3)当温度低于20度时,红灯长亮; 4)当湿度高于70%时,黄灯长亮; 5)当…

安卓实现微信聊天气泡

一搜没一个能用的&#xff0c;我来&#xff1a; 布局文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xml…

Tech Talk:智能电视eMMC存储的五问五答

智能电视作为搭载操作系统的综合影音载体&#xff0c;以稳步扩大的市场规模走入越来越多的家庭&#xff0c;成为人们生活娱乐的重要组成部分。存储部件是智能电视不可或缺的组成部分&#xff0c;用于保存操作系统、应用程序、多媒体文件和用户数据等信息。智能电视使用eMMC作为…

vue3中使用Antv G6渲染树形结构并支持节点增删改

写在前面 在一些管理系统中&#xff0c;会对组织架构、级联数据等做一些管理&#xff0c;你会怎么实现呢&#xff1f;在经过调研很多插件之后决定使用 Antv G6 实现&#xff0c;文档也比较清晰&#xff0c;看看怎么实现吧&#xff0c;先来看看效果图。点击在线体验 实现的功能…

服务端开发过程中常见的安全性问题

身份验证与授权 密码加密 加密传输 Https DDoS SQL注入 SQL注入的本质:数据和代码未分离&#xff0c;即数据当做了代码来执行。 解决办法 检查输入的数据是否符合预期&#xff0c;不能直接放入数据库中进行查询字符串长度验证mybatis具有防sql注入的方式 使用#{}代替${…

深入探讨光刻技术:半导体制造的关键工艺

前言 光刻&#xff08;Photolithography&#xff09;是现代半导体制造过程中不可或缺的一环&#xff0c;它的精度和能力直接决定了芯片的性能和密度。本文将详细介绍光刻技术的基本原理、过程、关键技术及其在半导体制造中的重要性。 光刻技术的基本原理 光刻是一种利用光化…

受限玻尔兹曼机浅析

受限玻尔兹曼机&#xff08;Restricted Boltzmann Machine&#xff0c;简称RBM&#xff09;是一种特殊的随机生成神经网络&#xff0c;能够学习并发现数据的复杂规则分布。以下是关于受限玻尔兹曼机算法的详细介绍&#xff1a; ⭐️ 定义与起源 定义&#xff1a; 受限玻尔兹…

深入剖析Tomcat(十四) Server、Service 组件:如何启停Tomcat服务?

通过前面文章的学习&#xff0c;我们已经了解了连接器&#xff0c;四大容器是如何配合工作的&#xff0c;在源码中提供的示例也都是“一个连接器”“一个顶层容器”的结构。并且启动方式是分别启动连接器和容器&#xff0c;类似下面代码 connector.setContainer(engine); try …

主流分布式消息中间件RabbitMQ、RocketMQ

分布式消息中间件在现代分布式系统中起着至关重要的作用。以下是一些主流的分布式消息中间件&#xff1a; 1. Apache Kafka - 特点&#xff1a;高吞吐量、低延迟、持久化、水平可扩展、分布式日志系统。 - 使用场景&#xff1a;日志收集与处理、实时流处理、事件驱动架构、大数…

NC204871 求和

链接 思路&#xff1a; 对于一个子树来说&#xff0c;子树的节点就包括在整颗树的dfs序中子树根节点出现的前后之间&#xff0c;所以我们先进行一次dfs&#xff0c;用b数组的0表示区间左端点&#xff0c;1表示区间右端点&#xff0c;同时用a数组来标记dfs序中的值。处理完dfs序…

小程序的运行机制、更新机制、生命周期介绍保姆级教程全解

一、小程序运行机制 1. 小程序冷启动 小程序启动可以分为两种情况&#xff0c;一种是冷启动&#xff0c;一种是热启动- 冷启动&#xff1a;如果用户首次打开&#xff0c;或小程序销毁后被用户再次打开&#xff0c;此时小程序需要重新加载启动- 热启动&#xff1a;如果用户已经打…

HSP_12章 Python面向对象编程oop_多态

文章目录 P128 多态问题的引出P129 多态细节和使用1. 多态介绍&特别说明2. 多态的好处3. 特别说明: Python多态的特点4. 使用多态的机制来解决主人喂食物的问题 P128 多态问题的引出 先看一个问题 # 说明: 先试用传统的方式完成 class Food:name Nonedef __init__(self,…

4.Android逆向协议-详解二次打包失败解决方案

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;微尘网校 上一个内容&#xff1a;3.Android逆向协议-APP反反编译及回编译 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.…