给定以下视图层次结构
root (e.g. view of a view controller)
  |_superview: A view where we will draw a cross using core graphics
    |_container: Clips subview
      |_subview: A view where we will show a cross adding subviews,which has to align perfectly with the cross drawn in superview
        |_horizontal line of cross
        |_vertical line of cross

任务:

在给定全局变换的情况下,superview和subview的十字架必须始终对齐. “要求”部分中的更多详细信息.

语境:

上面的视图层次结构属于图表.为了提供最大的灵活性,它允许提供图表点和&相关内容有3种不同的方式:

>在图表的基本视图(superview)中绘制绘制方法.
>将子视图添加到子视图.子视图在缩放/平移时进行转换,并自动显示其子视图.
>将子视图添加到子视图的同级中.为简单起见,未在视图层次结构中显示,因为它与问题无关.这里只提一下概述.这个方法和2.之间的区别在于,这里视图没有被转换,所以它留给内容的实现来“手动”更新所有子节点的转换.

最大的灵活性!但实现这一目标的成本实施起来有点棘手.具体点2.

目前我通过基本上分别处理超视图核心图形绘制和子视图的变换来进行缩放/平移工作,但是这导致冗余和容易出错,例如,重复的边界检查代码等

所以现在我正在尝试重构它以使用一个全局矩阵来存储所有变换并从中导出所有变换.将全局矩阵应用于superview用于绘制的坐标是微不足道的,但是根据下一节中列出的要求导出子视图矩阵,而不是如此.

我在视图层次结构部分提到了“十字架”,因为这是我在游乐场中使用的一个图表点的简化表示(使用x / y指南)(您可以向下滚动图像和要点).

要求:

>内容可以缩放和平移.
>十字架始终保持完美对齐.
>子视图的子视图,即无法触摸十字线视图(例如,将变换应用于它们) – 所有可以修改的都是子视图的变换.
>缩放和平移变换仅存储在全局矩阵矩阵中.
>然后使用矩阵计算在superview(平凡)中绘制的交叉的坐标,以及子视图的转换矩阵(不是平凡的 – 这个问题的原因).

>由于似乎不可能从全局矩阵中唯一地导出子视图矩阵,因此允许将其他数据存储在变量中,然后将这些变量与全局矩阵一起用于计运算符视图的矩阵.

>在缩放/平移期间,容器的大小/来源可能会发生变化.这样做的原因是y轴的标签可以具有不同的长度,并且图表需要动态地使内容大小适应标签占据的空间(在缩放和平移期间).
>当然,当容器的大小发生变化时,域 – 屏幕坐标的比例必须相应地改变,这样完整的原始可见域继续包含在容器中.例如,如果我在宽度为500pt的容器框架中显示带有域[0,10]的x轴,即将域点转换为屏幕坐标的比率为500/10 = 50,并收缩容器宽度为250,现在我的[0,10]域必须适合这个新宽度,其比率为25.
>它还必须为多个十字架(同时)和每个的任意域位置工作.这应该通过解决1-7自动发生,但提到完整性.

我做了什么:

以下是我试图更好地理解问题的逐步操场:

第1步(工作):

如开头所述构建层次结构,只显示在(编程)缩放期间必须保持对齐的十字架.泛.符合要求1,2,3,4和5:


Gist with playground.

特殊性:

>我跳过容器视图,以保持简单.子视图是superview的直接子视图.
> subview与superview具有相同的大小(当然是在缩放之前),也是为了保持简单.
>我将子视图的锚点设置为原点(0,0),这似乎是与全局矩阵同步的必要条件.
>必须记住用于锚更改的翻译,以便再次将其与全局矩阵一起应用.否则会被覆盖.为此,我使用变量subviewAnchorTranslation.这属于我在要求5下的子弹中想到的额外数据.

好吧,你看到一切都在这里工作.是时候尝试下一步了.

第2步(工作):

第1步操场的副本和修改:

>添加了容器视图,现在类似于开头描述的视图层次结构.
>为了使子视图(现在是容器的子视图继续显示在同一位置),必须通过-container.origin将其移动到顶部和左侧.
>现在,缩放和平移调用随机调用交错,以更改容器的帧位置/大小.

十字架继续保持同步.满足要求:全部来自第1步要求6.

Gist with playground

第3步(不起作用):

到目前为止,我一直在使用从0开始的屏幕范围(可见游乐场结果的左侧).这意味着容器不能满足其包含范围的功能,即要求7.为了满足这一要求,容器的原点必须包含在比率计算中.

现在还必须缩放子视图以适应容器/在正确的位置显示十字架.其中添加了第二个变量(首先是subviewAnchorTranslation),我称之为contentScalingFactor,包含此缩放,必须包含在子视图的矩阵计算中.

在这里,我做了多次实验,但都失败了.在当前状态下,子视图以与容器相同的框架开始,并且在容器框架更改时调整其框架的缩放比例.此外,子视图现在位于容器内,即它的原点现在是容器的原点而不是superview的原点,我必须设置更新其锚点,使得原点不在(0,0)但是(-x,-y),是x和y容器原点的坐标,使得子视图继续与superview的原点相关.每次容器更改其原点时更新此锚点似乎是合乎逻辑的,因为这会更改从内容的原点到superview的原点的相对位置.

我为此上传了代码 – 在这种情况下是一个完整的iOS项目,而不仅仅是一个游乐场(我最初认为它正在工作,并希望使用实际手势进行测试).在实际项目中,我正在努力改造工作,但我找不到差异.无论如何它不能很好地工作,在某些时候总是存在小的偏移并且点/交叉点不同步.


Github project

好的,我如何解决这个问题,以满足所有条件.十字架必须保持同步,连续缩放/平移并在两者之间改变容器的框架.

解决方法

本答案允许任意转换子层次结构中的任何视图.它不跟踪转换,只转换转换点,从而回答问题:

无论该子视图已被转换多少,位于另一视图的坐标系中的子视图中的点的坐标是什么.

为了将Parent与剪切容器分离并提供通用答案,我建议在概念上将它们放在同一级别,并在视觉上以不同的顺序放置(†):

使用常见的超级视图

要应用从子项到父项的滚动,缩放或任何其他转换,请通过公共超级视图(在本示例中命名为Coordinator).

该方法与this Stack Overflow answer非常相似,其中两个UIScrollView以不同的速度滚动.

注意红色细线和黑色细线如何重叠,无论位置,滚动,转换任何和所有关闭子层次结构中的视图,包括容器的视图.


↻ replay animation

协调转换

为简洁起见,在子视图的坐标系中使用任意点(50,50)(有效绘制该点),并在父视图系统中转换它,如下所示:

func coordinate() {
    let transfer = theChild.convert(CGPoint(x:50,y:50),to: coordinator)
    let final = coordinator.convert(transfer,to: theParent)
    theParent.transformed = final
    theParent.setNeedsdisplay()
}

放大&翻译容器

func zoom(center: CGPoint,delta: CGPoint) {
    theContainer.transform = theContainer.transform.scaledBy(x: delta.x,y: delta.y)
    coordinate()
}

func translate(delta: CGPoint) {
    theContainer.transform = theContainer.transform.translatedBy(x: delta.x,y: delta.y)
    coordinate()
}

(†)我已经分别将Superview和Subview重命名为Parent和Child.

ios – 同步超视图的变换矩阵和不同坐标空间中的各个视图的更多相关文章

  1. HTML利用九宫格原理进行网页布局

    这篇文章主要介绍了HTML利用九宫格原理进行网页布局,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – 将容器带到视图前方

    我怎样才能解决这个问题?

  4. ios – 如何使用XCode 6.4下载和替换AppGroup容器

    我知道如何使用XCode6的Devices窗口下载和替换特定iOS应用程序的文件系统容器.但是对于我正在开发的应用程序,我需要能够下载和替换共享的AppGroup容器以进行调试.这将使我能够模拟AppGroup文件夹内容中的情况以进行测试.任何人都可以告诉我如何做到这一点?

  5. ios – 在UITableView上移动UIView – 触摸顶部UIView仍然选择表行

    =======用一些代码编辑:这是我在容器B中所做的代码.这是B帧的一个非常直接的动画.self.view是ContainerB的UIView.所有视图都在屏幕上通过故事板.其他容器是B的子视图.请让我知道你想看到的其他代码.解决方法嗯……不确定这是否适用于您的情况,但尝试在容纳所有其他容器的更大容器中管理您的动画.我的意思是,创建一个包含A,B,O及其子视图的ContainerZ,并尝试从Z中设置B的位置动画,检查B是否在A前面.

  6. ios – 围绕x轴旋转AVAssetWriter的输出180度

    我正在使用AVAssetWriter创建一个Quicktime电影文件.目前输出视频是“倒置”.理论上,我可以通过围绕水平轴旋转180度来纠正这个问题.最好的方法是什么?Appledocs和wikipedia都没有明确说明仿射变换矩阵是如何工作的.并且可能有更好的方式.解决方法如果要围绕z轴旋转视频180度,或者如果你想在x轴上反射

  7. ios – 与容器视图通信的最佳实践是什么?

    我最近经常使用容器VC,我一直想知道主Vc和容器VC之间的最佳通信方式是什么.现在我正在使用通知,但我宁愿使用更好的东西.如何获取指向容器VC的指针,以便至少可以使用委托?

  8. ios – 编程嵌入UIViewController?

    我有一个带有一个容器视图的UIViewController的Storyboard设置,以便我可以在其中嵌入另一个UIViewController.在某种情况下,我需要更改嵌入式视图控制器.在我的故事板中,我的容器视图不能有两个区段.这导致我以编程方式进行.我的容器视图在我的故事板,没有连接的嵌入.现在从这一点开始,我如何以编程方式嵌入我所选择的UIViewController对象?

  9. ios – 使用Swift访问非默认的Cloudkit容器

    我有一个IOS8应用程序,它成功地将记录写入其默认的Cloudkit容器.现在我希望在OSX下的不同应用程序中读取和处理这些记录.我已经设置了具有iCloud访问权限的新应用程序,并选中了“指定自定义容器”选项.这已成功找到原始应用程序和我的容器没有错误要在Capabilities界面上修复.我的所有搜索都告诉我“同一个开发人员签署的两个应用程序可能共享同一个容器”但我找不到的任何教程文档都告诉我

  10. ios – 嵌入在容器视图中的UINavigationController,显示大小错误的表视图控制器

    我正在尝试找到解决这种情况的方法:我有一个UITabBarController它的一个segue连接到一个容器视图控制器(BannerViewController),我用来嵌入一个UINavigationController,导航控制器推送其他容器视图控制器(EventListContainerviewController),每个包含一个tableview控制器.这是我的故事板上的一个屏幕问题是最

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部