【问题标题】:How to make a view scroll? Just like Instagram's profile如何使视图滚动?就像 Instagram 的个人资料一样
【发布时间】:2025-12-23 18:20:19
【问题描述】:

滚动视图中的 UIView、SegmentedController 和 UIContainerView 或类似的东西?

在我的故事板中,我有一个 VC,其中包含顶部的 UIView、中间的分段控制器和底部的 2 个 ContainerViewControllers,并将 segue 嵌入到新的 VC。

在新的 VC 中,我有一个 TableView 和一个 CollectionView(例如 Instagram 个人资料)。

我的问题是我需要 SegmentedController 和 UIView 与 ContainerView(TableView/CollectionView) 一起滚动,目前只有 ContainerView 部分滚动并且上面的部分是固定的。

现在我猜我可能需要将所有内容都放入 UIScrollView,所以我尝试了并正确放置了所有成本约束。但是当它在 Swift 文件中配置它时,我现在才真正知道如何设置滚动的高度,但显然我需要的高度可以变化并且不是固定高度!

如果有人可以在这里帮助我,那就太棒了,或者可能会指出我已经在这里提出的类似问题?我已经看过了,但很遗憾没有找到任何东西!

下面的图片基本上解释了我所追求的,如果上面我不是很清楚..

这是一个你可以看到的例子:https://github.com/Jackksun/ScrollIssue

【问题讨论】:

  • 保持赏金开放,当我回家时,我会用一个工作代码示例更新我的答案
  • @thibautnoah 嘿,你找到解决方案了吗?
  • 你为什么不直接使用tableViewController
  • @lukesIvi 好吧,我现在实际上是,这是我想要实现的几个 tableview 的屏幕截图:i.stack.imgur.com/q3dSJ.png i.stack .imgur.com/gFBqt.png 正如您所看到的,即使它们在 tableview 中,collectionview 仍然会自行滚动,而不是与 tableview/(整个视图)
  • @Jack 编辑回复

标签: ios swift uiview uiscrollview


【解决方案1】:

据我了解,您想让滚动视图在其边界之外接收触摸。您可以通过覆盖实际接收触摸的视图上的 hitTest:withEvent: 方法来实现这一点。

这是我在项目中所做的一个示例。我将 UIView 子类化并将其接收到的所有触摸重定向到特定视图。在您的情况下,您会将所有触摸重定向到滚动视图。

.h file:

@import UIKit.UIView;

/*!
 @class         TouchableView
 @abstract      Touchable view.
 */
@interface TouchableView : UIView

/*!
 @property      viewToReceiveTouches
 @abstract      View that receives touches instead of a given view.
 */
@property (nonatomic, weak) IBOutlet UIView *viewToReceiveTouches;

@end
.m file:

@import UIKit.UIButton;
@import UIKit.UITableView;
@import UIKit.UITextField;

#import "TouchableView.h"

@implementation TouchableView

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ( [self shouldViewReceiveTouch:self inPoint:point] )
    {
        return [super hitTest:point withEvent:event];
    }
    else if ( CGRectContainsPoint(self.bounds, point) && self.isUserInteractionEnabled )
    {
        return self.viewToReceiveTouches;
    }

    return nil;
}

- (BOOL)shouldViewReceiveTouch:(UIView *)view inPoint:(CGPoint)point
{
    if ( !CGRectContainsPoint(view.bounds, point) || !view.isUserInteractionEnabled )
    {
        return NO;
    }

    if ( [view isKindOfClass:[UIButton class]] ||
         [view isKindOfClass:[UITextField class]] ||
         [view isKindOfClass:[UITableViewCell class]] ||
         [view isKindOfClass:[UITableView class]] )

    {
        return YES;
    }

    for ( UIView *subview in view.subviews )
    {
        if ( [self shouldViewReceiveTouch:subview inPoint:[view convertPoint:point toView:subview]] )
        {
            return YES;
        }
    }

    return NO;
}

@end

【讨论】:

  • 您好,谢谢您,我只是将其放入 Swift 代码中,以便我更好地理解它!我想要实现的有点像 instagram 个人资料,您在其中拥有 uisegmented 控制器,但所有视图都是可滚动的
  • 至少重写代码总是更好,而不仅仅是复制粘贴它:)
  • 嘿,它并不完全有效,但它确实让我走上了正确的道路!谢谢你,我设法弄明白了
【解决方案2】:

您可以为滚动视图内容设置动态大小。这就是我所做的。

  • 定义dynamicHeight 来存储新的TableView/CollectionView 高度。
  • 每次更改段控件时,获取子控制器高度并更新滚动视图内容大小。

看看我的代码(演示here

@IBAction func selectPage(sender: AnyObject) {

    // clear all child controller before load new controller 
    for controller in childViewControllers {

        controller.removeFromParentViewController()
    }

    for view in pageContainer.subviews {

        view.removeFromSuperview()
    }

    let segment = sender as! UISegmentedControl

    if segment.selectedSegmentIndex == 0 {

        createImageController()
    }
    else {

        createTextController()
    }

    updateScrollContentSize()
}

func updateScrollContentSize() {

    // 150 is your view and segment height
    scrollView.contentSize = CGSize(width: view.frame.size.width, height: dynamicHeight + 150)
}

func createTextController() {

    let textController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("TextController") as! TextController
    dynamicHeight = textController.getTableContentHeight()
    textController.tableView.scrollEnabled = false

    self.addChildViewController(textController)
    pageContainer.addSubview(textController.view)
    textController.view.frame = CGRectMake(0, 0, pageContainer.frame.size.width, dynamicHeight)
}

func createImageController() {

    let imageController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ImageShowController") as! ImageShowController
    dynamicHeight = imageController.getTableContentHeight()
    imageController.tableView.scrollEnabled = false

    self.addChildViewController(imageController)
    pageContainer.addSubview(imageController.view)
    imageController.view.frame = CGRectMake(0, 0, pageContainer.frame.size.width, dynamicHeight * 2)
}

希望这会有所帮助。

【讨论】:

  • 您好,谢谢您,我已经玩了一段时间了。但是在我的 tableView&CollectionView 中,我不知道它们将是多少图像,可能是 3 或可能是 30。从您的代码中,我了解您根据多少图像计算视图的高度,我有尝试做类似的,但它似乎不工作! (我正在使用 Parse 下载我的图像)如果它们是一种在不知道它们将有多少图像/高度的情况下执行此操作的方法,那就太好了!
  • 添加一个代理以在下载完成后更新您的 tableView/collectionView。请看我的演示,我在那里更新新代码。
  • 我刚试过,这是我看到的(和以前一样)i.stack.imgur.com/9DHIN.png 然后当我点击另一个选项卡并返回第一个选项卡时什么都没有出现?
  • 我的演示在您下载时运行良好吗?如果您愿意,我们可以通过 Skype 进行对话:nguyentruongky3390。希望我能帮上忙。
  • 演示效果很好,是的,但是当您下载图像时似乎不起作用......或者当它没有计算高度时......我应该设置一个连接到解析的演示项目吗?
【解决方案3】:

由于您的身高可能会有所不同,我认为做您想做的最简单的方法是将所有内容放入UICollectionView。 赛格?没问题,实现didSelectRowAtIndexPath,更改您的数据和高度并重新加载UICollectionView。 您还可以将UICollectionView 添加到简单的UIView,这样您就可以在其上放置一些静态内容。

这是一个示例应用程序来演示这一点: https://github.com/tirrorex/Apps/tree/master/Swift/Sampleapp

您将必须实现一个动态高度,您可以在此找到一些线程(基本上您可以为包含您的 collectionview/tableview 的单元格制作一个特殊情况,以便从 nib 加载该单元格,这可能会对您有所帮助) : UICollectionView Self Sizing Cells with Auto Layout

【讨论】:

  • 什么意思?将分段控制器等全部放在 collectionView 中?
  • 是的,这正是我的意思。您的 vc 的每个组件都将成为 collectionview 的特定单元格(如果您不需要太多自定义,则为 tableview)。因此,每个单元格都是一个 uiview,并且您将每个组件添加为子视图,这将允许您删除和更新特定元素而无需触及其余部分。
  • 如果我将 UIView 放入 tableViewCell,那么我将无法创建 IBOutlets 来连接到该 UIVIew 中的项目(例如 Labels、ImageViews...)。我确实尝试在 tableView 中执行您提到的操作,但我总是收到类似这样的错误:IBOutlets cannot be connected to possible repeating cells (something similar about)
  • 无法隐藏是什么意思?您不需要插座,您可以在代码中创建按钮。您可以实现 didSelectRowAtIndexPath 或为您的按钮设置一些操作。
  • 我没有看到问题,更改您的数据源并相应地重新加载 tableview/collectionview,我这样做是为了拖放和展开/折叠。表格视图中的简单方法是将您不想要 atm 的单元格的高度设置为零,它会隐藏它而无需更改任何内容。
最近更新 更多