iOS,创建自定义弹出窗口样式 UIView

iOS, create custom popover style UIView

我知道有很多关于这个主题的文档,从我读到的内容中我学到了很多。我这里的问题是,我开始在 viewcontroller 中创建自定义 UIView,现在当我试图让它成为自己的 UIView 时 class,以便在工作应用程序中调用和使用,我很困惑我需要做什么才能实现它。

class 的总体目标是能够 select 一个按钮一个视图控制器,它将实例化自定义视图,然后显示。用户的视觉效果是他们单击按钮,然后 window 将从按钮的边界动画出现(尽管下面的代码当前使用左上角的定位),然后显示开关组合和标签,以及后退和保存按钮。

你可以从我的代码中看到我需要实现这个过程,我已经设法将其实现为一个函数(同样,这是在 viewcontroller 中创建的)。我现在想知道的是要导入自定义视图,然后在主视图控制器按钮的操作上,将视图添加到 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;
    }];
}

我明白,因为我是 doing/calling 通过代码实现的,所以我需要覆盖 initinitWithFrame:。我是否传递 initWithFrame: 包含的视图控制器边界,可以在其中计算自定义视图,我如何处理动画?

我已经成功设置了委托协议,该协议将在按下保存按钮时发出通知。这部分我明白了,其他部分我不清楚。

首先介绍一下背景。

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

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

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

UIPopoverController 与某些第 3 方弹出窗口一样执行此操作。有些甚至使用他们自己的 UIWindows。

回答您的具体问题:

1) initWithFrame: / setFrame: 应该传递一个 CGRect,它位于将包含该视图的视图的坐标 space 中。换句话说,超级视图。如果您决定使用透明根视图,弹出窗口(在屏幕上绘制的部分)将在透明根视图的坐标 space 中传递一个 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;
                 }
];

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

这是我所做的:

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;
    }];

}

然后在我们的父级viewcontroller

@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!");
}