【问题标题】:Change the width of Master in UISplitViewController在 UISplitViewController 中改变 Master 的宽度
【发布时间】:2010-06-01 10:48:45
【问题描述】:

iPad 编程指南说 splitView 的左窗格固定为 320 点。但是我的主视图控制器的 320 像素太多了。我想减少它并为细节视图控制器提供更多空间。到底有没有可能?

链接到document,它谈到了固定宽度。

【问题讨论】:

标签: ios uisplitviewcontroller ipad


【解决方案1】:

如果你继承 UISplitViewController,你可以实现-viewDidLayoutSubviews 并在那里调整宽度。这是干净的,没有 hack 或私有 API,甚至可以旋转。

- (void)viewDidLayoutSubviews
{
    const CGFloat kMasterViewWidth = 240.0;

    UIViewController *masterViewController = [self.viewControllers objectAtIndex:0];
    UIViewController *detailViewController = [self.viewControllers objectAtIndex:1];

    if (detailViewController.view.frame.origin.x > 0.0) {
        // Adjust the width of the master view
        CGRect masterViewFrame = masterViewController.view.frame;
        CGFloat deltaX = masterViewFrame.size.width - kMasterViewWidth;
        masterViewFrame.size.width -= deltaX;
        masterViewController.view.frame = masterViewFrame;

        // Adjust the width of the detail view
        CGRect detailViewFrame = detailViewController.view.frame;
        detailViewFrame.origin.x -= deltaX;
        detailViewFrame.size.width += deltaX;
        detailViewController.view.frame = detailViewFrame;

        [masterViewController.view setNeedsLayout];
        [detailViewController.view setNeedsLayout];
    }
}

【讨论】:

  • 我不明白为什么会这样,因为没有使用私有 API。
  • 好收获。编辑了我的答案。
  • 这应该是公认的答案。当 Apple 可以轻松暴露设置时,Apple 让您像这样跳过箍,这很荒谬,但我很高兴您分享了这一点。
  • 黑屏仅在 iOS 8 上发生。在 iOS 8 上,您不需要此代码 - 请改用 maximumPrimaryColumnWidth。在 iOS 7 上,不会出现黑屏,@jrc 的解决方案有效。
  • 避免无限循环:iOS8 中的一些变化是导致无限循环的原因。为了避免这种情况,我们使用了上面的代码,但是将它包装在一个检查 iOS 版本的 if() 块中。如果小于8.0,则使用上面的代码,否则,只需设置:self.maximumPrimaryColumnWidth = masterViewWidth;请为这个解决方案投票@SJTriggs 和 Twan 的答案。
【解决方案2】:

在 IOS 8.0 中,您可以通过以下操作轻松做到这一点:

1.在您的 MasterSplitViewController.h 添加

@property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0);

2。在您的 MasterSplitViewController.m viewDidLoad 方法中添加

 self.maximumPrimaryColumnWidth = 100;
 self.splitViewController.maximumPrimaryColumnWidth = self.maximumPrimaryColumnWidth;

这是IOS 8的一个非常好的,简单易用的功能。

【讨论】:

  • 有谁能给我提供这个代码的 Swift 等价物吗?我似乎无法在 Swift 项目中使用它。
  • 没关系,我设法找到了解决方案(虽然有点不同)stackoverflow.com/questions/2949067/…
  • 与 iOS 10 GM、xCode 8 和 Swift 2.3 一起使用。它就像一个魅力! :)
【解决方案3】:

这段代码对我有用

[splitViewController setValue:[NSNumber numberWithFloat:200.0] forKey:@"_masterColumnWidth"];

【讨论】:

  • 恐怕我们会在这种情况下更改私有属性。最好不要这样做。谁知道,Apple 可能会决定改变其类层次结构?
  • @Raj @pryiyanka,你肯定会在应用商店中被拒绝。
  • 是的,这就是我实现自己的SplitViewController的原因,当时Matt Gamell的splitViewController并不存在,但现在你可以使用MGSplitViewController,它很好。
  • 在 iOS 9 下仍然可以工作,现在在 iOS 10 下它崩溃了!
  • iOS10会崩溃
【解决方案4】:

没有。


有两个私有属性

@property(access,nonatomic) CGFloat masterColumnWidth;
@property(access,nonatomic) CGFloat leftColumnWidth; // both are the same!

但私有意味着它们不能用于 AppStore 应用程序。

【讨论】:

  • 谢谢,但我不会使用私有 API,而是实现自己的拆分视图控制器。 . .
  • @Raj 我如何继承 UISplitViewController 并且只覆盖 masterColumnWidth?
  • @Kyle - 如果您想将应用提交到应用商店,则不能采用上述方法。否则,如果您仍然坚持使用它,则不必对其进行子类化。请参阅下面的答案:stackoverflow.com/a/4022406/260665
  • @Raj - 我需要提交到 App Store。有没有办法以 Apple 接受的方式使用您建议的答案?我假设答案是一个子类,还是那也很糟糕?
  • 不,不,为了后代,我正在更改接受的答案。如果您想提交到应用商店,您不能使用这种方法,甚至不能子类化和更改宽度。它肯定会被拒绝。使用 Matt Gemmell 的拆分视图控制器。请参阅我接受的新答案。
【解决方案5】:

iOS 8 引入了一个新属性:

// An animatable property that can be used to adjust the maximum absolute width of the primary view controller in the split view controller.
@property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0); // default: UISplitViewControllerAutomaticDimension

使用此属性将主视图控制器调整为所需的宽度。

【讨论】:

  • 因为有很多不同的屏幕尺寸,你最好使用preferredPrimaryColumnWidthFraction
【解决方案6】:

这是我在 iOS8 中使用 Swift 的方法。

class MainSplitViewController: UISplitViewController {

    override func viewDidLoad() {

        self.preferredDisplayMode = UISplitViewControllerDisplayMode.AllVisible
        self.maximumPrimaryColumnWidth = 100 // specify your width here
    }
}

如果您需要在拆分视图的主/详细视图中动态更改宽度,请执行以下操作:

var splitViewController = self.splitViewController as MainSplitViewController
splitViewController.maximumPrimaryColumnWidth = 400

【讨论】:

  • 将 splitViewController.maximumPrimaryColumnWidth = ### 添加到您的 appdelegate.swift
【解决方案7】:

故事板的方式是@Tim 提到的这种方式:

此外,如果您希望主视图始终占据屏幕的某个百分比,那么您可以使用 Key Path = "preferredPrimaryColumnWidthFraction" 并将值设置为 0.2(对于 20% 的屏幕大小)。

请注意,“maximumPrimaryColumnWidth”设置为 320,因此如果您尝试屏幕百分比值 0.5 (50%),它不会超过 320。如果您需要覆盖,可以为 maximumPrimaryColumnWidth 添加一个关键路径这个。

【讨论】:

    【解决方案8】:

    在 iOS7 上没有一个对我有用的答案,所以我做了一些自己的研究并创建了一个可行的解决方案。这将涉及子类化 UISplitViewController 以获得完整功能。

    我将给出答案,就好像我们刚刚为 iPad 创建了一个具有所有设备方向的新项目,并将自定义 UISplitViewController 设置为主视图控制器。

    创建您的自定义UISplitViewController。在这个例子中,我的被称为MySplitViewController。所有代码都将基于MySplitViewController.m

    我们需要从UISplitViewControllerDelegate 访问一个方法,所以添加它并设置委托。我们还将设置一个委托转发器,以防您需要从另一个类调用委托方法。

    @interface MySplitViewController () <UISplitViewControllerDelegate>
    @property (nonatomic, weak) id<UISplitViewControllerDelegate> realDelegate;
    @end
    
    @implementation MySplitViewController
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            self.delegate = self;
        }
        return self;
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            self.delegate = self;
        }
        return self;
    }
    
    - (void)setDelegate:(id<UISplitViewControllerDelegate>)delegate {
        [super setDelegate:nil];
        self.realDelegate = (delegate != self) ? delegate : nil;
        [super setDelegate:delegate ? self : nil];
    }
    
    - (BOOL)respondsToSelector:(SEL)aSelector {
        id delegate = self.realDelegate;
        return [super respondsToSelector:aSelector] || [delegate respondsToSelector:aSelector];
    }
    
    - (id)forwardingTargetForSelector:(SEL)aSelector {
        id delegate = self.realDelegate;
        return [delegate respondsToSelector:aSelector] ? delegate : [super forwardingTargetForSelector:aSelector];
    }
    

    设置主视图控制器和详细视图控制器。

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        UIViewController* masterViewController = [[UIViewController alloc] init];
        masterViewController.view.backgroundColor = [UIColor yellowColor];
    
        UIViewController* detailViewController = [[UIViewController alloc] init];
        detailViewController.view.backgroundColor = [UIColor cyanColor];
    
        self.viewControllers = @[masterViewController, detailViewController];
    }
    

    让我们将我们想要的宽度添加到一个方法中以便于参考。

    - (CGFloat)desiredWidth {
        return 200.0f;
    }
    

    我们将在展示主视图控制器之前对其进行操作。

    - (void)splitViewController:(UISplitViewController *)svc popoverController:(UIPopoverController *)pc willPresentViewController:(UIViewController *)aViewController {
        id realDelegate = self.realDelegate;
    
        if ([realDelegate respondsToSelector:@selector(splitViewController:popoverController:willPresentViewController:)]) {
            [realDelegate splitViewController:svc popoverController:pc willPresentViewController:aViewController];
        }
    
        CGRect rect = aViewController.view.frame;
        rect.size.width = [self desiredWidth];
        aViewController.view.frame = rect;
    
        aViewController.view.superview.clipsToBounds = NO;
    }
    

    但是,现在我们只剩下这样的显示了。

    所以要重写一个私有方法。是的,一个私有方法,它在 App Store 中仍然可以接受,因为它不是下划线私有方法。

    - (CGFloat)leftColumnWidth {
        return [self desiredWidth];
    }
    

    这涉及纵向模式。 -splitViewController:willShowViewController:invalidatingBarButtonItem: 也有类似的情况,您应该设置为横向。

    但是在 iOS8 中这些都不需要。您将能够简单地调用最小和最大宽度属性!

    【讨论】:

      【解决方案9】:

      在分配给 rootviewcontroller 之前使用以下代码。它适用于 ios7

      [self.splitViewController setValue:[NSNumber numberWithFloat:256.0] forKey:@"_masterColumnWidth"]; self.window.rootViewController = self.splitViewController;

      【讨论】:

        【解决方案10】:

        由于没有人提到这可以从 IB 完成,我想添加这个答案。显然,您可以使用以下详细信息为 UISplitViewContorller 设置“用户定义的运行时属性”: 关键路径:masterColumnWidth 类型:数字 价值:250

        【讨论】:

          【解决方案11】:

          就我而言,我必须同时设置最大值和最小值才能完成这项工作

          mySplitViewController.preferredDisplayMode = .allVisible;
          mySplitViewController.maximumPrimaryColumnWidth = UIScreen.main.bounds.width/2;
          mySplitViewController.minimumPrimaryColumnWidth = UIScreen.main.bounds.width/2; 
          

          【讨论】:

            【解决方案12】:

            您可以使用GSSplitViewController。这个适用于 iOS 7 和 8

            splitView = [[GSSplitViewController alloc] init];
            splitView.masterPaneWidth = 180;
            

            您也可以通过将pod 'GSSplitViewController' 添加到您的Podfile 来包含它。

            【讨论】:

              【解决方案13】:

              ViewController.h @property(nonatomic, assign) CGFloat maximumPrimaryColumnWidth NS_AVAILABLE_IOS(8_0);

              ViewController.m

              #define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
              
                  if (SYSTEM_VERSION_LESS_THAN(@"10.0")) {
              
                  [self setValue:[NSNumber numberWithFloat:200.0]forKey:@"_masterColumnWidth"];
              
                  }else{
              
                  self.maximumPrimaryColumnWidth = 200;
                  self.splitViewController.maximumPrimaryColumnWidth = self.maximumPrimaryColumnWidth;
              
                   }
              

              【讨论】:

                【解决方案14】:

                你使用的 Swift 3.0 喜欢

                let widthfraction = 2.0 //Your desired value for me 2.0    
                splitViewController?.preferredPrimaryColumnWidthFraction = 0.40
                let minimumWidth = min((splitViewController?.view.bounds.size.width)!,(splitViewController?.view.bounds.height)!)
                splitViewController?.minimumPrimaryColumnWidth = minimumWidth / widthFraction
                splitViewController?.maximumPrimaryColumnWidth = minimumWidth / widthFraction
                let leftNavController = splitViewController?.viewControllers.first as! UINavigationController
                leftNavController.view.frame = CGRect(x: leftNavController.view.frame.origin.x, y: leftNavController.view.frame.origin.y, width: (minimumWidth / widthFraction), height: leftNavController.view.frame.height)
                

                【讨论】:

                  【解决方案15】:
                  // in UISplitViewController subclass
                  // let more space for detail in portrait mode
                  - (void)viewWillLayoutSubviews
                  {
                      CGFloat width;
                      if (UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication.statusBarOrientation)){
                          width = CGRectGetWidth(self.view.bounds) * 0.25f;
                      }
                      else {
                          width = CGRectGetWidth(self.view.bounds) * 0.33f;
                      }
                      width = (NSInteger)fminf(260, fmaxf(120, width));
                      self.minimumPrimaryColumnWidth = width;
                      self.maximumPrimaryColumnWidth = width;
                  
                      [super viewWillLayoutSubviews];
                  }
                  

                  【讨论】:

                    【解决方案16】:

                    这段代码对我有用:)

                    @interface UISplitViewController(myExt) 
                    - (void)setNewMasterSize:(float)size; 
                    @end

                    @implementation UISplitViewController(myExt) - (void)setNewMasterSize:(float)size { _masterColumnWidth = 大小; } @结尾

                    并在每个有视图的操作上使用它(如旋转)

                    【讨论】:

                    • 我知道可以使用类似这样的类别修改私人信息,但这是我第二次尝试并得到相同的错误:“_OBJC_IVAR_$_UISplitViewController._masterColumnWidth”,引用自:_OBJC_IVAR_$_UISplitViewController UISplitViewController+myExt.o 中的 ._masterColumnWidth$non_lazy_ptr(也许您的意思是:_OBJC_IVAR_$_UISplitViewController._masterColumnWidth$non_lazy_ptr)符号未找到。 Collect2: ld 返回 1 个退出状态
                    猜你喜欢
                    • 2014-10-24
                    • 2011-12-23
                    • 1970-01-01
                    • 1970-01-01
                    • 2011-05-31
                    • 1970-01-01
                    • 1970-01-01
                    • 2023-03-18
                    • 1970-01-01
                    相关资源
                    最近更新 更多