如何在iOS中创建UIActionSheet的背景视图?

时间:2018-03-25 14:46:30

标签: ios objective-c swift uialertcontroller

我希望UIActionSheet拥有自定义UIAlertAction,但似乎自定义UIAlertAction不合法。

  

UIAlertController类旨在按原样使用,不支持子类化。此类的视图层次结构是私有的,不得修改。

所以我尝试创建一个看起来与UIActionSheet完全相同的视图。通过使用Debug View Hierarchy,我可以知道Apple如何应用UIActionSheet的层次结构,约束,颜色来完成他们所做的事情。

enter image description here

我可以创建除UIActionSheet背景之外的所有内容。它是一个包含非透明视图和UIVisualEffectView的视图。

UIVisualEffectView重叠非透明视图,但某种程度上UIVisualEffectView仍有效。

enter image description here

如果UIVisualEffectView下面有不透明的内容,它仍然有用吗?如果有可能,我该如何制作这样的东西?

注意:UIActionSheet的背景不仅仅是UIVisualEffectView。请不要给出这样的答案。

2 个答案:

答案 0 :(得分:3)

UIVisualEffectView下方的视图(问题中带有红色箭头的视图)包含一个图层,该图层将CAFilter“overlayBlendMode”(私有类)设置为合成过滤器。它应用于它背后的层。在下面的屏幕截图中,我将_UIDimmingKnockoutBackdropView的背景颜色更改为绿色,并将过滤器应用于此。

enter image description here

隐私方法

要创建相同的效果,您需要在UIVisualEffectView下方放置一个白色不透明视图并对其应用CAFilter:

CAFilter *filter = [CAFilter filterWithName:@"overlayBlendMode"];
[[contentView layer] setCompositingFilter:filter];

由于CAFilter是私有的,我们需要一个标题:

#import <Foundation/Foundation.h>

@interface CAFilter : NSObject <NSCoding, NSCopying, NSMutableCopying> {
    void * _attr;
    void * _cache;
    unsigned int  _flags;
    NSString * _name;
    unsigned int  _type;
}

@property BOOL cachesInputImage;
@property (getter=isEnabled) BOOL enabled;
@property (copy) NSString *name;
@property (readonly) NSString *type;

// Image: /System/Library/Frameworks/QuartzCore.framework/QuartzCore

+ (void)CAMLParserStartElement:(id)arg1;
+ (BOOL)automaticallyNotifiesObserversForKey:(id)arg1;
+ (id)filterTypes;
+ (id)filterWithName:(id)arg1;
+ (id)filterWithType:(id)arg1;

- (void)CAMLParser:(id)arg1 setValue:(id)arg2 forKey:(id)arg3;
- (id)CAMLTypeForKey:(id)arg1;
- (struct Object { int (**x1)(); struct Atomic { struct { int x_1_2_1; } x_2_1_1; } x2; }*)CA_copyRenderValue;
- (BOOL)cachesInputImage;
- (id)copyWithZone:(struct _NSZone { }*)arg1;
- (void)dealloc;
- (BOOL)enabled;
- (void)encodeWithCAMLWriter:(id)arg1;
- (void)encodeWithCoder:(id)arg1;
- (id)initWithCoder:(id)arg1;
- (id)initWithName:(id)arg1;
- (id)initWithType:(id)arg1;
- (BOOL)isEnabled;
- (id)mutableCopyWithZone:(struct _NSZone { }*)arg1;
- (id)name;
- (void)setCachesInputImage:(BOOL)arg1;
- (void)setDefaults;
- (void)setEnabled:(BOOL)arg1;
- (void)setName:(id)arg1;
- (void)setValue:(id)arg1 forKey:(id)arg2;
- (id)type;
- (id)valueForKey:(id)arg1;

// Image: /System/Library/PrivateFrameworks/PhotosUICore.framework/PhotosUICore

+ (id)px_filterWithPXCompositingFilterType:(int)arg1;

@end

结果: enter image description here

我创建的视图打印与Apple使用的相同的合成过滤器: enter image description here

解决方法

作为一种解决方法,您可以在背景上创建视图图像,并在白色视图中创建图像,并应用叠加混合模式。这导致与使用私有类的结果相当。

示例:

    UIImage *image = [self imageForView:contentView];
    UIView *superview = [contentView superview];

    [contentView setHidden:YES];
    UIImage *backgroundImage = [self imageForView:superview];
    CGImageRef imageRef = CGImageCreateWithImageInRect([backgroundImage CGImage], [contentView frame]);
    backgroundImage = [UIImage imageWithCGImage:imageRef]; 
    CGImageRelease(imageRef);
    [contentView setHidden:NO];

    CIFilter *filter = [CIFilter filterWithName:@"CIOverlayBlendMode"];
    [filter setValue:[backgroundImage CIImage] forKey:kCIInputImageKey];
    [filter setValue:[image CIImage] forKey:kCIInputBackgroundImageKey];
    [contentView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageWithCIImage:[filter outputImage]]]];
}

- (UIImage *)imageForView:(UIView *)view
{
    UIGraphicsBeginImageContextWithOptions([view bounds].size, [view isOpaque], 1.0);
    [[view layer] renderInContext:UIGraphicsGetCurrentContext()];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;
}

结果: enter image description here

答案 1 :(得分:1)

请检查我的故事板视图设置和结果。 我使用具有相同图像的实际苹果动作表来控制结果。

设置故事板 enter image description here

<强>结果 enter image description here

原创苹果的行动表 enter image description here

实现自定义操作表的方法之一 您可以查看Apple的文档以获取动态堆栈视图Dynamically Changing the Stack View’s Content