目标c:使用设备方向异步更新UIView

Posted

技术标签:

【中文标题】目标c:使用设备方向异步更新UIView【英文标题】:Objective c:Asynchronously update UIView with device orientation 【发布时间】:2012-07-01 08:57:36 【问题描述】:

我遇到了在设备方向到位的情况下异步更新 UIView 的问题。我已经在 viewDidload 中实现了设备方向,如下所示

- (void)viewDidLoad
[super viewDidLoad];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged) name:UIDeviceOrientationDidChangeNotification object:nil];
[self initialize];

在orientationChanged方法中,我有以下代码

-(void)orientationChanged 
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

if(UIInterfaceOrientationIsLandscape(orientation))
    UINib *nib = [UINib nibWithNibName:@"ConsoleViewControllerLandscape" bundle:nil];
    UIView *portraitView = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
    self.view = portraitView;

    [self initialize];

 else 
    UINib *nib = [UINib nibWithNibName:@"ConsoleViewController" bundle:nil];
    UIView *portraitView = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
    self.view = portraitView;

    [self initialize];


在初始化方法中,我实际上使用类似代码异步更新 UI

 [self performSelectorOnMainThread:@selector(arrangeAsynchronously) withObject:nil waitUntilDone:NO];
- (void) arrangeAsynchronously
    //Some complex calculation and finally
[self.view addSubview:imageview];

问题是当方向改变的图像视图没有添加到主视图时。假设我从纵向视图开始,然后我可以在纵向视图中查看所有图像视图,如果它更改为横向,则视图为空白。如果我再次切换到纵向,那么所有子视图(即 imageViews)都会正确添加。问题是当方向改变时,我正在加载一个新的 nib 文件,但是代码仍然是指从旧的 nob 文件加载的旧视图。如何更改参考。仅当我在异步模式下执行此操作时才会出现此问题。

这不是 uiview 的问题,而是设备旋转后计算子视图位置的问题。早些时候我的代码是

CGAffineTransform inverseTransform = CGAffineTransformInvert(self.view.transform);
fixedPoint = CGPointApplyAffineTransform(fixedPoint,inverseTransform);
fixedPoint = CGPointMake(fixedPoint.x+126, fixedPoint.y-109);

我把它改成了

fixedPoint = CGPointMake(fixedPoint.x+126, fixedPoint.y-109);

但我仍然不知道为什么仿射变换不起作用 waitUntilDone:NO 并且在 waitUntilDone:YES 中起作用。

【问题讨论】:

【参考方案1】:

你的策略有点问题。 self.view 以某种方式呈现,仅仅因为您创建了一个新的 UIView,并不意味着它会在呈现的窗口中被替换。

我建议您在主UIView(您在此处替换的那个)添加一个容器视图,然后在更改设备方向时更改容器视图的内容。

编辑

我的回答可能看起来有点不清楚,所以让我试着更详细地解释一下。 UIViewControllerUIViewUIWindow 表示。这意味着窗口具有对视图的引用。当您更改UIViewControllerUIView(通过构造新的UIView)时,并不意味着它将反映在UIWindow 中。


初始场景:

UIViewController->UIView1

在你构造一个新的 UIView 之后:

UIViewController->UIView2 UIWindow->UIView1


正如您在上图中看到的,您没有生成任何错误,但是您现在有两个视图,并且在您的 UIViewController 中所做的更改不会反映在屏幕上。

你可能很幸运,它第一次工作:如果你重建 UIView 在 UIWindow 呈现它之前一切仍然有效,但它仍然是一个糟糕的设计,可能很容易破坏(就像你一样时间改变后看看)。

这是实际可行的情况:


初始场景:

*UIViewController->UIView1

在你构造一个新的 UIView 之后:

*UIViewController->UIView2

窗口在屏幕上显示视图:

UIViewController->UIView2


基本上你不应该把你的句柄扔给UIViewUIViewController

我希望这有助于您理解引用/指针的工作原理。

【讨论】:

现在很酷的编码器。我正在努力帮助你。让我尝试更详细地解释一下我认为您的设计存在的问题;您的视图控制器中有一个视图,您可以在每次手机倾斜时重建该视图。但是在某处你有一个 UIWindow 或另一个视图控制器,它仍然引用了第一个视图。这意味着即使您构建了一个新视图,您也不会得到它的呈现。基本上:你永远不应该在呈现后重建 UIViewController 的视图。我希望这能澄清一点,-也请尽量保持友好的语气。 感谢您的建议,我想解释的是,当我使用 [self performSelectorOnMainThread:@selector(arrangeAsynchronously) withObject:nil waitUntilDone:NO] 更新视图时会出现问题;但是当waitUntilDone:YES时问题没有出现。这意味着,问题不是因为 View 表示,而是与线程有关。让我知道这是否有意义。 执行选择器中的 waitUntilDone YES/NO 之间的区别在于何时执行代码,而不是执行操作的线程。请尝试我建议的解决方案。如果这没有帮助,我们可以讨论下一步。

以上是关于目标c:使用设备方向异步更新UIView的主要内容,如果未能解决你的问题,请参考以下文章

当我在 iOS 的目标 c 中异步发送请求时,为啥我的数据会损坏?

c#winform不是用this.dispatcher.invoke来异步更新ui吗?

Swift 4:设备旋转后 UI 无法更新

如何修复不更新 UI 的目标 c 应用程序?

根据 API 的响应异步更新进度条

UIScrollVIew 中的 UIView 不更新视图