【问题标题】:iOS, create custom popover style UIViewiOS,创建自定义弹出框样式 UIView
【发布时间】:2015-03-22 09:41:03
【问题描述】:

我知道有很多关于这个主题的文档,并且从我所阅读的内容中我学到了很多东西。我的问题是,我开始在视图控制器中创建自定义 UIView,现在当我尝试将其作为 UIView 自己的类,以便在工作应用程序中调用和使用时,我很困惑什么我需要做才能实现它。

该类的总体目标是能够选择一个按钮一个视图控制器,它将实例化自定义视图,然后显示。用户的视觉效果是他们点击按钮,然后一个窗口会从按钮的边界动画出现(虽然下面的代码目前使用左上角的定位),然后显示开关和标签的组合,沿着带有后退和保存按钮。

您可以从我的代码中看到我需要实现这个过程,我已经设法将其实现为一个函数(同样,这是通过在视图控制器中创建它)。我现在所追求的,不能完全理解的是要导入自定义视图,然后在主视图控制器按钮的操作上,将视图添加到 self.view。

- (void)makeBox{
    //view bounds
    CGFloat viewWidth = CGRectGetWidth(self.view.frame);
    CGFloat viewHeight = CGRectGetHeight(self.view.frame);

    //red box x, y & size
    CGFloat startx = (viewWidth / 100) * 10;
    CGFloat starty = (viewHeight /100) * 20;
    CGFloat width = (viewWidth / 100) * 80;
    CGFloat height = (viewHeight /100) * 70;
    CGRect view1Frame = CGRectMake(startx, starty, width, height);

    //label & switch frame
    CGRect labelMR = CGRectMake(10, ((height / 100) * 12), ((width / 100) * 80) - 7.5, 25);
    CGRect switchMR = CGRectMake(((width / 100) * 80) + 7.5, ((height / 100) * 11), ((width / 100) * 10), 15);

   //this is repeated for 6 other labels & switches

    CGRect backButtonR = CGRectMake(5, 5,  50, 35);
    CGRect saveButtonR = CGRectMake((width - 50), 5, 50, 35);

    if (!self.view1) {
        self.switchM = [[UISwitch alloc] initWithFrame:switchMR];
        self.switchM.tag = 10;
        if(self.monday){ //self.monday refers to a BOOL property of the viewcontroller that this was originally made in
            self.switchM.on = true;
        } else{
            self.switchM.on = false;
        }
        [self.switchM addTarget:self action:@selector(switched:) forControlEvents:UIControlEventTouchUpInside];

        // this switch instantiation process is repeated 6 other times 

        self.backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [self.backButton addTarget:self
                            action:@selector(hideBox)
                  forControlEvents:UIControlEventTouchUpInside];
        [self.backButton setTitle:@"Back" forState:UIControlStateNormal];
        self.backButton.frame = backButtonR;


        self.saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [self.saveButton addTarget:self
                            action:@selector(daysChanged)
                  forControlEvents:UIControlEventTouchUpInside];
        [self.saveButton setTitle:@"Save" forState:UIControlStateNormal];
        self.saveButton.frame = saveButtonR;


        self.labelM = [[UILabel alloc] initWithFrame:labelMR];
        self.labelM.layer.masksToBounds = YES;
        self.labelM.layer.cornerRadius = 5;
        self.labelM.layer.borderColor = [UIColor blackColor].CGColor;
        self.labelM.layer.borderWidth = .5;
        self.labelM.text = @" Monday";
        self.labelM.backgroundColor = [UIColor whiteColor];

        //again - repeated 6 times

        //use this starting frame to make the 'popover' appear small at first
        CGRect startFrame = CGRectMake(10, 10, 10, 10);

        self.view1 = [[UIView alloc] initWithFrame:startFrame];

        [self.view addSubview:self.view1];
        [UIView animateWithDuration:0.5 animations:^(void){

            self.view1.layer.cornerRadius = 10;
            self.view1.layer.borderColor = [UIColor blackColor].CGColor;
            self.view1.layer.borderWidth = .5;
            [self.view1 setBackgroundColor:[UIColor lightGrayColor]];


            self.view1.frame = view1Frame;

        } completion:^(BOOL finished){

            [self.view1 addSubview:self.labelM];
            [self.view1 addSubview:self.switchM];
            //repeat 6 times for other labels & switches
        }];

    }
    else {
        [UIView animateWithDuration:0.3 animations:^() {
            self.view1.frame = view1Frame;

        } completion:^(BOOL finished) {
            self.labelM.frame = labelMR;
            self.switchM.frame = switchMR;

           //repeated for the other 6

            self.backButton.frame = backButtonR;
            self.saveButton.frame = saveButtonR;
        }];
    }
}

-(void) hideBox{
    //back button was selected
    [UIView animateWithDuration:0.5 animations:^(void){
        [self.view1 removeFromSuperview];
        self.view1 = nil;
    }];
}

我了解,当我通过代码执行/调用此操作时,我需要覆盖 initinitWithFrame:。我是否通过 initWithFrame: 包含视图控制器边界,可以计算自定义视图,以及如何处理动画?

我已经设法设置了委托协议,当按下保存按钮时会发出通知。这部分我理解,只是我不清楚的其余部分。

【问题讨论】:

    标签: ios objective-c uiview


    【解决方案1】:

    首先是一些背景。

    通常对于弹出框控制器,您有一个透明的根视图,其中包含弹出框视图本身。此根视图是包含窗口的大小,通常在 z 顺序中高于所有其他视图。这有两个原因:

    1) 弹出框需要绘制在所有其他视图之上。如果根视图不在所有其他视图之上,则弹出框可能会被剪裁而不绘制其所有内容。

    2) 用户通常需要某个地方来点击和关闭弹出框(实际上是取消操作)。

    UIPopoverController 和一些第 3 方弹出框一样执行此操作。有些人甚至使用他们自己的 UIWindows。

    回答您的具体问题:

    1) initWithFrame: / setFrame: 应该传递一个CGRect,它位于将包含该视图的视图的坐标空间中。换句话说,超级视图。如果您决定使用透明根视图,弹出框(在屏幕上绘制的部分)将在透明根视图的坐标空间中传递一个 CGRect。

    2) 通常弹出框的动画是这样的:

    // set initial frame
    popover.frame = CGRectMake(x, y, width, 0);
    popover.alpha = 0.0;
    [rootView addSubview:popover];
    
    [UIView animateWithDuration:0.5
                     animations:^{
                       CGRect frame = popover.frame;
                       frame.size.height = some-height;
                       popover.frame = frame;
                       popover.alpha = 1;
                     }
    ];
    

    【讨论】:

    • 我正在开发 iPhone 应用程序,我相信 UIPopoverController 不适用于 iphone。我明白你关于在根视图中保持弹出的观点,但这不会限制我为每个使用它的视图重写代码吗?自发布问题以来,我已经取得了一些进展(我会尽快更新问题以反映这一点)。拆分init、openbox和update box的功能。
    • 是的,UIPopoverViewController 在 iPhone 上不可用,但有 3rd 方弹出控制器可用,您可以通过 cocoapods 轻松集成它们。话虽如此,理想情况下,您为 popover 编写的任何代码都将具有非常相似的 UIPopoverController 的 API/接口,即:给它一些内容、委托并在特定位置显示它。
    • 好吧,我确实得到了一些工作!我敢肯定它并不完美,但概念就在那里 :) 感谢您的帮助!
    【解决方案2】:

    我真的让它工作了! (虽然我不能保证这是最干净或最足智多谋的方式 - 我们会努力的)。

    这就是我所做的:

    makeBox 函数拆分为 3 个函数,initWithWidth:andHeight:forViewopenBoxupdateBoxWithWidth:andHeight。 我使用了一个saveButton 委托方法来通知父级已按下保存按钮。

    .h

        @protocol BoxDelegate
        -(void) daysChanged;
        @end
        __weak id <BoxDelegate> delegate;
        @interface aBox : UIView
        @property (nonatomic) BOOL monday;
        @property (nonatomic, weak) id <BoxDelegate> delegate;
        //property values for the custom view
    
        -(id) initWithWidth: (CGFloat) width andHeight: (CGFloat) height withView: (UIView*) theView;
        -(void) updateViewWithWidth: (CGFloat) width andHeight: (CGFloat) height;
        -(void) openBox;
    
        @end
    

    .m

        @synthesize delegate;
        -(id) initWithWidth:(CGFloat)inWidth andHeight:(CGFloat)inHeight withView: (UIView*) theView{
        self = [super init];
    
        self.mainView = theView;
        //super view bounds
        self.viewWidth = inWidth;
        self.viewHeight = inHeight;
    
        //red box x, y & size
        CGFloat startx = (self.viewWidth / 100) * 10;
        CGFloat starty = (self.viewHeight /100) * 20;
        self.width = (self.viewWidth / 100) * 80;
        self.height = (self.viewHeight /100) * 70;
        self.view1Frame = CGRectMake(startx, starty, self.width, self.height);
    
        //label & switch frame
        self.labelMR = CGRectMake(10, ((self.height / 100) * 12), ((self.width / 100) * 80) - 7.5, 25);
        self.switchMR = CGRectMake(((self.width / 100) * 80) + 7.5, ((self.height / 100) * 11), ((self.width / 100) * 10), 15);
    
        //repeated for the other 6
        self.backButtonR = CGRectMake(5, 5,  50, 35);
        self.saveButtonR = CGRectMake((self.width - 50), 5, 50, 35);
    
    
        self.switchM = [[UISwitch alloc] initWithFrame:self.switchMR];
        self.switchM.tag = 10;
        if(self.monday){
            self.switchM.on = true;
        } else{
            self.switchM.on = false;
        }
        [self.switchM addTarget:self action:@selector(switched:) forControlEvents:UIControlEventTouchUpInside];
    
        self.labelM = [[UILabel alloc] initWithFrame:self.labelMR];
        self.labelM.layer.masksToBounds = YES;
        self.labelM.layer.cornerRadius = 5;
        self.labelM.layer.borderColor = [UIColor blackColor].CGColor;
        self.labelM.layer.borderWidth = .5;
        self.labelM.text = @" Monday";
        self.labelM.backgroundColor = [UIColor whiteColor];
    
        //repeated for the other 6
        self.saveButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [self.saveButton addTarget:delegate
                            action:@selector(daysChanged)
                  forControlEvents:UIControlEventTouchUpInside];
        [self.saveButton setTitle:@"Save" forState:UIControlStateNormal];
        self.saveButton.frame = self.saveButtonR;
        return self;
    }
    
    
    -(void) openBox{
        CGRect startFrame = CGRectMake(10, 10, 10, 10);
    
        self.view1 = [[UIView alloc] initWithFrame:startFrame];
    
        [self.mainView addSubview:self.view1];
        [UIView animateWithDuration:0.5 animations:^(void){
    
            self.view1.layer.cornerRadius = 10;
            self.view1.layer.borderColor = [UIColor blackColor].CGColor;
            self.view1.layer.borderWidth = .5;
            [self.view1 setBackgroundColor:[UIColor lightGrayColor]];
    
             // repeated for the other 6
    
            self.view1.frame = self.view1Frame;
    
        } completion:^(BOOL finished){
            [self.view1 addSubview:self.labelM];
            [self.view1 addSubview:self.switchM];
    
            [self.view1 addSubview:self.backButton];
            [self.view1 addSubview:self.saveButton];
    
    
        }];
    }
    
    -(void) updateViewWithWidth: (CGFloat) width andHeight:(CGFloat) height{
    
        //re-calculate
        self.viewWidth = width;
        self.viewHeight = height;
    
        CGFloat startx = (self.viewWidth / 100) * 10;
        CGFloat starty = (self.viewHeight /100) * 20;
        self.width = (self.viewWidth / 100) * 80;
        self.height = (self.viewHeight /100) * 70;
        self.view1Frame = CGRectMake(startx, starty, self.width, self.height);
    
        //label & switch frame
        self.labelMR = CGRectMake(10, ((self.height / 100) * 12), ((self.width / 100) * 80) - 7.5, 25);
        self.switchMR = CGRectMake(((self.width / 100) * 80) + 7.5, ((self.height / 100) * 11), ((self.width / 100) * 10), 15);
    
        self.backButtonR = CGRectMake(5, 5,  50, 35);
        self.saveButtonR = CGRectMake((self.width - 50), 5, 50, 35);
    
        [UIView animateWithDuration:0.3 animations:^() {
            self.view1.frame = self.view1Frame;
    
        } completion:^(BOOL finished) {
            self.labelM.frame = self.labelMR;
            self.switchM.frame = self.switchMR;
            self.backButton.frame = self.backButtonR;
            self.saveButton.frame = self.saveButtonR;
        }];
    
    }
    

    然后在我们的父视图控制器中

    @property aBox *theBox;
    ...
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.theBox = [[aBox alloc] initWithWidth:self.view.frame.size.width andHeight:self.view.frame.size.height withView:self.view];
        [self.theBox openBox];
    
    }
    
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
        [self.theBox updateViewWithWidth:self.view.frame.size.width andHeight:self.view.frame.size.height];
    }
    - (void) daysChanged{
         NSLog(@"Days Changed!");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-09
      • 1970-01-01
      • 2017-03-11
      • 1970-01-01
      • 2017-06-08
      • 2019-06-29
      • 1970-01-01
      相关资源
      最近更新 更多