草庐IT

ios - 如何以编程方式滚动我的整个 View ,包括图像

coder 2024-01-28 原文

我有这样的布局:

它由一个 UINavigationController 组成,其中包含一个 UIScrollView

该 View 包含一个 UIImage 和一个 UILabel

标签中的文本可能会很长,如果发生这种情况,我想滚动整个 View 以使其可滚动,包括图像。

我已经尝试嵌入一个 UIScrollView 并将其锚定到顶部和底部,但是无法让图像滚动,只有标签。

我没有尝试将我的父 View 设置为 UIScrollView。这是行不通的

class ContentView: UIScrollView {

    private var margins: UILayoutGuide!
    private var activity: UIActivityIndicatorView!

    private var articleImageView: UIImageView!
    private var articleTextView: UILabel!

    override init(frame: CGRect) {
        super.init(frame: frame)

        margins = safeAreaLayoutGuide

        isScrollEnabled = true

        articleImageView = UIImageView(image: #imageLiteral(resourceName: "feed_header_bg"))
        articleImageView.contentMode = .scaleAspectFill

        addSubview(articleImageView)
        articleImageView.anchor(top: margins.topAnchor, leading: margins.leadingAnchor, bottom: nil, trailing: margins.trailingAnchor)


        articleTextView = UILabel(frame: .zero)

        articleTextView.numberOfLines = 0

        articleTextView.text = "foo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nboo\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbaz"

        addSubview(articleTextView)
        articleTextView.anchor(top: articleImageView.bottomAnchor, leading: margins.leadingAnchor, bottom: nil, trailing: margins.trailingAnchor)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func addLoadingView() {
        activity = UIActivityIndicatorView(style: .whiteLarge)
        activity.color = .black
        activity.isHidden = true
        addSubview(activity)
        activity.anchor(centerX: centerXAnchor, centerY: centerYAnchor)
        activity.startAnimating()
    }
}

我也在使用一个扩展来帮助编程自动布局

struct AnchoredConstraints {
    var top, leading, bottom, trailing, width, height: NSLayoutConstraint?
}

extension UIView {
    @discardableResult
    func anchor(top: NSLayoutYAxisAnchor? = nil, leading: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, trailing: NSLayoutXAxisAnchor? = nil, padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints {
        translatesAutoresizingMaskIntoConstraints = false
        var anchoredConstraints = AnchoredConstraints()

        if let top = top {
            anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top)
        }

        if let leading = leading {
            anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left)
        }

        if let bottom = bottom {
            anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom)
        }

        if let trailing = trailing {
            anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right)
        }

        if size.width != 0 {
            anchoredConstraints.width = widthAnchor.constraint(equalToConstant: size.width)
        }

        if size.height != 0 {
            anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height)
        }

        [anchoredConstraints.top, anchoredConstraints.leading, anchoredConstraints.bottom, anchoredConstraints.trailing, anchoredConstraints.width, anchoredConstraints.height].forEach { $0?.isActive = true }

        return anchoredConstraints
    }

    func anchor(
        top: NSLayoutYAxisAnchor? = nil, left: NSLayoutXAxisAnchor? = nil, bottom: NSLayoutYAxisAnchor? = nil, right: NSLayoutXAxisAnchor? = nil,
        paddingTop: CGFloat = 0, paddingLeft: CGFloat = 0, paddingBottom: CGFloat = 0, paddingRight: CGFloat = 0,
        width: CGFloat = 0, height: CGFloat = 0,
        centerX: NSLayoutXAxisAnchor? = nil, centerY: NSLayoutYAxisAnchor? = nil
        ) {
        translatesAutoresizingMaskIntoConstraints = false

        if let top = top {
            self.topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
        }

        if let left = left {
            self.leadingAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
        }

        if let bottom = bottom {
            self.bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
        }

        if let right = right {
            self.trailingAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
        }

        if width != 0 {
            widthAnchor.constraint(equalToConstant: width).isActive = true
        }

        if height != 0 {
            heightAnchor.constraint(equalToConstant: height).isActive = true
        }

        if let centerX = centerX {
            self.centerXAnchor.constraint(equalTo: centerX).isActive = true
        }

        if let centerY = centerY {
            self.centerYAnchor.constraint(equalTo: centerY).isActive = true
        }
    }


    func fillSuperview(padding: UIEdgeInsets = .zero) {
        translatesAutoresizingMaskIntoConstraints = false
        if let superviewTopAnchor = superview?.topAnchor {
            topAnchor.constraint(equalTo: superviewTopAnchor, constant: padding.top).isActive = true
        }

        if let superviewBottomAnchor = superview?.bottomAnchor {
            bottomAnchor.constraint(equalTo: superviewBottomAnchor, constant: -padding.bottom).isActive = true
        }

        if let superviewLeadingAnchor = superview?.leadingAnchor {
            leadingAnchor.constraint(equalTo: superviewLeadingAnchor, constant: padding.left).isActive = true
        }

        if let superviewTrailingAnchor = superview?.trailingAnchor {
            trailingAnchor.constraint(equalTo: superviewTrailingAnchor, constant: -padding.right).isActive = true
        }
    }

    func centerInSuperview(size: CGSize = .zero) {
        translatesAutoresizingMaskIntoConstraints = false
        if let superviewCenterXAnchor = superview?.centerXAnchor {
            centerXAnchor.constraint(equalTo: superviewCenterXAnchor).isActive = true
        }

        if let superviewCenterYAnchor = superview?.centerYAnchor {
            centerYAnchor.constraint(equalTo: superviewCenterYAnchor).isActive = true
        }

        if size.width != 0 {
            widthAnchor.constraint(equalToConstant: size.width).isActive = true
        }

        if size.height != 0 {
            heightAnchor.constraint(equalToConstant: size.height).isActive = true
        }
    }
}



我想在顶部有一个图像,在下面有一个文本,如果文本不适合 View ,则允许用户滚动。

最佳答案

您可以尝试子类化 UIView 并添加 UIScroll 并设置 anchor 吗?

我能够复制它并且它现在似乎对我有用

class ContentView: UIView {
    private var sv: UIScrollView!

    override init(frame: CGRect) {
        super.init(frame: frame)

        sv = UIScrollView(frame: .zero)
        sv.backgroundColor = .purple

        addSubview(sv)
        sv.fillSuperview()

        let ai = UIImageView(image: #imageLiteral(resourceName: "feed_header_bg"))
        ai.contentMode = .scaleToFill

        sv.addSubview(ai)
        ai.anchor(
            top: sv.topAnchor, left: sv.leadingAnchor, bottom: nil, right: sv.trailingAnchor,
            paddingTop: 20, paddingLeft: 20, paddingBottom: 0, paddingRight: 20,
            width: 0, height: 0,
            centerX: sv.centerXAnchor, centerY: nil
        )

        let l = UILabel(frame: .zero)
        l.numberOfLines = 0
        l.text = """
        Bacon ipsum dolor amet turkey jowl sausage, fatback pork chop kevin frankfurter cupim leberkas picanha ground round swine andouille buffalo meatloaf. Kielbasa meatloaf filet mignon tail. Spare ribs strip steak pork belly t-bone tongue pork loin. Hamburger tenderloin prosciutto venison bacon buffalo.

        Shankle andouille sausage shank capicola kevin, pork loin beef ribs pig leberkas short loin prosciutto jerky beef. Swine kevin pork chop, ribeye cupim short loin boudin buffalo beef. Leberkas filet mignon beef ribs turducken, ribeye sausage shoulder t-bone. Capicola leberkas tail, salami buffalo doner brisket prosciutto sirloin pork loin pork chop ribeye spare ribs drumstick.

        Picanha tongue cow jowl landjaeger cupim meatball sausage kielbasa strip steak pork loin chuck jerky venison biltong. Leberkas capicola bacon, pork loin ground round venison strip steak swine picanha tail flank andouille. Ball tip shankle ham hock leberkas swine. Ball tip sirloin boudin chicken, ground round tail jowl ribeye bresaola. Beef ribs shankle rump jowl chuck cow frankfurter capicola. Sausage picanha short ribs porchetta. Picanha drumstick corned beef beef ribs meatball leberkas pancetta.

        Shankle pancetta kevin hamburger fatback jerky shoulder frankfurter alcatra flank meatloaf rump. Burgdoggen rump shank sirloin hamburger chicken turducken cupim tail andouille ham hock ribeye fatback. Swine pork belly bacon pork chop pig jowl. Drumstick shankle pork loin ham hock, bresaola filet mignon kielbasa.

        Drumstick tongue pork loin pork belly turducken, pig porchetta ground round pancetta bacon pastrami strip steak venison. Tail cow doner pig, beef venison filet mignon landjaeger shank. Swine ham hock burgdoggen picanha shankle capicola tail prosciutto. Short loin ball tip pork chop turkey, pork loin chuck pork shankle salami. Buffalo short ribs sausage doner shankle, filet mignon pancetta frankfurter short loin. Pastrami burgdoggen strip steak, ground round swine shank sirloin pork loin hamburger jowl ribeye. Buffalo turducken kielbasa pork capicola ground round tri-tip drumstick bacon.
        """

        sv.addSubview(l)
        l.anchor(
            top: ai.bottomAnchor, left: sv.leadingAnchor, bottom: sv.bottomAnchor, right: sv.trailingAnchor,
            paddingTop: 20, paddingLeft: 0, paddingBottom: 0, paddingRight: 0,
            width: 0, height: 0,
            centerX: sv.centerXAnchor, centerY: nil
        )
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

关于ios - 如何以编程方式滚动我的整个 View ,包括图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54340754/

有关ios - 如何以编程方式滚动我的整个 View ,包括图像的更多相关文章

  1. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  4. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  5. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  6. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  7. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  8. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  9. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  10. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

随机推荐