【问题标题】:How can I create a view like background view of UIActionSheet in iOS?如何在 iOS 中创建类似于 UIActionSheet 的背景视图的视图?
【发布时间】:2018-03-25 14:46:30
【问题描述】:

我想要一个带有自定义UIAlertActionUIActionSheet,但似乎自定义UIAlertAction 是不合法的。

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

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

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

UIVisualEffectView 与非透明视图重叠,但不知何故 UIVisualEffectView 仍然有效。

UIVisualEffectView 下面有一个不透明的时候怎么还能工作?如果可能的话,我怎样才能做出这样的事情?

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

【问题讨论】:

  • 你想做什么?我有点困惑。
  • 我想要一个UIView,其模糊效果与操作表背景的效果完全一样。
  • 好的,知道了。我认为你应该用代码做到这一点

标签: ios objective-c swift uialertcontroller


【解决方案1】:

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

私有方法

要创建相同的效果,您需要在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

结果:

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

解决方法

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

例子:

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

结果:

【讨论】:

  • 你知道你说的视图是白色和不透明的背景吗?尝试创建这样的东西,你就会知道它是否可能。
  • 当您为compositingFilter 属性提供CIFilter 时,您将得到compositingFilter = &lt;CIOverlayBlendMode: inputImage=nil inputBackgroundImage=nil&gt; 而不是compositingFilter = overlayBlendMode
  • 另外,您应该编辑以前的答案而不是创建新答案。
  • 由于所有反应都不是基于我的新答案,而且旧答案可能对其他人有用,我创建了一个新答案。 CIFilter 与 Apple 内部使用的 CAFilter 不同,这就是打印的描述不同的原因(我也尝试复制它)。所以不可能完全确定 Apple 如何在 UIAlertController 中创建视图/层的背景。我们只能猜测如何复制它。 (获取compositingFilter的类:[[[view layer] compositingFilter] class])
  • 请关注我的问题:UIVisualEffectView 下面有一个不透明的时候怎么还能工作?如果可能的话,我怎么能做这样的事情? 如果你知道答案,请给我你的答案。不要说这是不可能的或类似的事情。如果不是,请不要给出任何答案。我不想给你投反对票
【解决方案2】:

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

故事板设置

结果

原苹果的操作表

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

【讨论】:

  • 抱歉,我不明白你的问题的重点。能详细解释一下吗?
  • 我正在尝试重现操作表所需的效果。哪个部分不清楚?我将添加更多细节。尝试以与我在故事板中相同的方式排列视图,以检查此效果是否适合您
  • 现在我明白了,但你应该仔细检查效果。看起来他们是一样的,但他们不是。您可以使用颜色选择器检查同一点的颜色,以比较您的自定义视图和操作表背景。
  • 图像位置略有不同,这就是颜色选择器可以提供不同结果的原因。也可能他们有不同的 alpha(不是 0.1)我认为这是最接近的选择之一。为什么需要精确的像素到像素样式?
  • 您可以移动视图的位置以使其相同。对于你为什么的问题,只是为了满足我的好奇心,Apple 是如何做到的;)
猜你喜欢
  • 1970-01-01
  • 2012-03-17
  • 2012-06-04
  • 2018-01-21
  • 1970-01-01
  • 2014-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多