มุมมองเบลอสไตล์ iOS 7


113

มีใครรู้บ้างเกี่ยวกับการควบคุมใด ๆ ที่จะจำลองมุมมองเบลอสไตล์ iOS7

ฉันสมมติว่าอาจมีคลาสย่อย UIView บางประเภทที่จะจำลองพฤติกรรม

ฉันกำลังพูดถึงมุมมองประเภทนี้ซึ่งเบลอฉากหลังอย่างหนามากจนมีเอฟเฟกต์ดึงจากมุมมองพื้นหลัง

ใส่คำอธิบายภาพที่นี่


6
GPUImageอาจช่วยได้
Maarten

@ อย่างนั้นคำถามจะเกิดขึ้นเมื่อ ios7 SDK เปิดตัวฉันจะทำสิ่งนี้ได้อย่างไรโดยไม่ จำกัด แอปของฉันไว้ที่ ios7 เท่านั้น;)
endy


1
Apple ได้เปิดตัวหมวด UIImage ที่ทำสิ่งนี้ได้ เพียงแค่พยายามค้นหามัน
Fogmeister

1
รหัสเชื่อมโยงจากเซสชัน WWDC 201 เป็นสาธารณะบน github ฉันไม่พบ atm
Fogmeister

คำตอบ:


40

คุณอาจสามารถแก้ไขบางอย่างเช่นRWBlurPopoverของ Bin Zhang เพื่อทำสิ่งนี้ได้ ส่วนประกอบนั้นใช้ GPUImage ของฉันเพื่อใช้ Gaussian เบลอกับส่วนประกอบที่อยู่ด้านล่าง แต่คุณสามารถใช้ CIGaussianBlur ได้อย่างง่ายดายเช่นเดียวกัน GPUImage อาจจะมีผมเร็วขึ้นแม้ว่า

ส่วนประกอบนั้นขึ้นอยู่กับว่าคุณสามารถจับภาพมุมมองเบื้องหลังของที่คุณกำลังนำเสนอได้และอาจมีปัญหากับมุมมองที่เคลื่อนไหวอยู่เบื้องหลังเนื้อหานี้ ความจำเป็นในการเดินทางผ่าน Core Graphics เพื่อแรสเตอร์มุมมองพื้นหลังจะทำให้สิ่งต่าง ๆ ช้าลงดังนั้นเราอาจไม่มีสิทธิ์เข้าถึงโดยตรงเพียงพอที่จะสามารถทำได้ในลักษณะที่มีประสิทธิภาพสำหรับการซ้อนทับในมุมมองภาพเคลื่อนไหว

จากการอัปเดตข้างต้นฉันเพิ่งปรับปรุงการเบลอใน GPUImage เพื่อรองรับรัศมีตัวแปรทำให้สามารถจำลองขนาดเบลอได้อย่างสมบูรณ์ในมุมมองศูนย์ควบคุมของ iOS 7 จากนั้นฉันได้สร้างคลาส GPUImageiOS7BlurFilter ที่สรุปขนาดความเบลอและการแก้ไขสีที่เหมาะสมซึ่งดูเหมือนว่า Apple จะใช้ที่นี่ นี่คือความเบลอของ GPUImage (ทางด้านขวา) เมื่อเปรียบเทียบกับความเบลอในตัว (ทางด้านซ้าย):

ความเบลอของ Apple ความเบลอของ GPUImage

ฉันใช้การสุ่มตัวอย่าง / การสุ่มตัวอย่างแบบ 4X เพื่อลดจำนวนพิกเซลที่ต้องใช้การเบลอแบบเกาส์ดังนั้น iPhone 4S สามารถเบลอหน้าจอทั้งหมดได้ในเวลาประมาณ 30 มิลลิวินาทีโดยใช้การดำเนินการนี้

คุณยังคงมีความท้าทายในการดึงเนื้อหาเข้าสู่ความเบลอจากมุมมองเบื้องหลังเนื้อหานี้ในลักษณะที่มีประสิทธิภาพ


คุณคิดว่า Apple กำลังดึงมันออกมาได้อย่างไร? หากคุณเปิดแอพกล้องและดึงศูนย์ควบคุมขึ้น (หน้าจอการตั้งค่าจากด้านล่าง) ความเบลอจะเป็นไปตามสิ่งที่กล้องมองเห็น
Snowman

2
@maq - ช่วยให้สามารถเข้าถึงทุกอย่างในระบบได้ภายใต้ฝากระโปรง สิ่งที่ผู้พัฒนาระบบปฏิบัติการสามารถทำได้นั้นแตกต่างอย่างมากกับสิ่งที่อินเตอร์เฟสสาธารณะให้เราทำ
Brad Larson

3
@maq - ฟีดกล้องโดยเฉพาะใช่ วิธีหนึ่งในการทำเช่นนี้คือการใช้ GPUImage เพื่อดึงเฟรมของกล้อง (ผ่าน AV Foundation) จากนั้นให้เอาต์พุตทั้งสองไปยัง GPUImageView สำหรับเอาต์พุตกล้องถ่ายทอดสดจากนั้นจะป้อนแบบขนานในภาพเบลอแบบเกาส์เซียน (และอาจเป็นการครอบตัด เพื่อให้ตรงกับตำแหน่งของมุมมองที่เบลอ) และเอาต์พุตนั้นไปยัง GPUImageView อื่นที่จะแสดงเนื้อหาเบลอหลังการควบคุมของคุณ เป็นไปได้เพราะเรามีเส้นทางที่รวดเร็วจากเฟรมกล้องไปยัง OpenGL ES แต่เราไม่มีองค์ประกอบ UI ทั่วไปที่คล้ายกัน
Brad Larson

1
ฉันกำลังถ่ายภาพหน้าจอของ UIView โดยใช้โปรแกรมและใช้ GPUImageGaussianBlurFilter เพื่อพยายามสร้างเอฟเฟกต์ที่คล้ายกัน แต่ผลลัพธ์จะแตกต่างจากรูปแบบของ Apple มาก ดูเหมือนว่าฟิลเตอร์จะเบลอเป็นเส้นตารางโดยมีช่องสี่เหลี่ยมที่มองเห็นได้ทุกที่โดยที่ของ Apple เป็นเพียงแผ่นเรียบแผ่นเดียว
Snowman

1
@maq - ตรวจสอบให้แน่ใจว่าคุณใช้รหัสล่าสุดจากที่เก็บเนื่องจากก่อนหน้านี้มีจุดบกพร่องที่รัศมีเบลอสูง ที่กล่าวว่าการเบลอจะสุ่มตัวอย่างเฉพาะพื้นที่ 9 พิกเซลตามค่าเริ่มต้นดังนั้นหากคุณเพิ่มตัวคูณสำหรับความเบลอที่ผ่านมาจุดนั้นคุณจะเริ่มเห็นสิ่งประดิษฐ์จากการข้ามพิกเซล สิ่งนี้ทำด้วยเหตุผลด้านประสิทธิภาพ แต่คุณสามารถแก้ไขจุดยอดและแฟรกเมนต์เชเดอร์เพื่อสุ่มตัวอย่างพิกเซลจำนวนมากขึ้น หรือลองใช้ CIGaussianBlur ซึ่งมีการใช้งานเบลอทั่วไป วันหนึ่งฉันจะขยายความเบลอนี้เป็นรัศมีที่ใหญ่ขึ้น
Brad Larson

28

ฉันใช้FXBlurViewซึ่งใช้งานได้ดีบน iOS5 +

https://github.com/nicklockwood/FXBlurView

CocoaPods:

-> FXBlurView (1.3.1)
   UIView subclass that replicates the iOS 7 realtime background blur effect, but works on iOS 5 and above.
   pod 'FXBlurView', '~> 1.3.1'
   - Homepage: http://github.com/nicklockwood/FXBlurView
   - Source:   https://github.com/nicklockwood/FXBlurView.git
   - Versions: 1.3.1, 1.3, 1.2, 1.1, 1.0 [master repo]

ฉันเพิ่มโดยใช้:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];

2
มีเคล็ดลับในการใช้ FXBlurView หรือไม่? ฉันได้ลองใช้แล้ว แต่เราส่งผลให้เกิดการดูล่าช้าใน iPhone 5 โครงการสาธิตของพวกเขาทำงานได้ดี ค่อนข้างแปลก
วิกฤต

ขึ้นอยู่กับว่าคุณต้องการทำอะไร เมื่อฉันวางFXBlurViewทับUIScrollViewฉันก็ได้ผลลัพธ์ที่ล้าหลังเช่นกัน ฉันเชื่อว่าสิ่งนี้เกี่ยวข้องกับวิธีการเพิ่มความเบลอ Apple คือถ้าฉันไม่ได้เข้าใจผิดจะเข้าถึง GPU โดยตรงเมื่อใช้การเบลอของตัวเองซึ่งเราไม่สามารถทำได้ในฐานะนักพัฒนา ดังนั้นโซลูชัน @cprcrack จึงเป็นทางออกที่ดีที่สุดที่นี่
Paul Peelen

2
คุณจัดการการหมุนอุปกรณ์ด้วย FXBlurView อย่างไร? ฉันกำลังนำเสนอกล่องโต้ตอบโมดอลในขณะนี้ กล่องโต้ตอบเองก็หมุนได้ดี แต่ฉากหลังถูกทำลายผิดทาง (จำเป็นต้องอัปเดตหลังจากการหมุนโดยทั่วไป)
fatuhoku

1
แน่นอนว่า FXBlurView เป็นตัวเลือกที่ดี แต่เมื่อมีเรื่องของการใช้งาน CPU มากกว่าที่ฉันชอบอื่น ๆ ฉันใช้สิ่งนี้ใน UICollectionVIew และ UITableView แต่เพิ่มการใช้งาน CPU ของฉัน ในการรันครั้งต่อไปฉันแสดงความคิดเห็นการจัดสรรเหล่านั้นและมันกลายเป็นเรื่องปกติ ฉันหวังว่านี่จะช่วยใครบางคนได้
Vatsal Shukla

27

คำเตือน: มีคนแสดงความคิดเห็นระบุว่า Apple ปฏิเสธแอปที่ใช้เทคนิคนี้ นั่นไม่ได้เกิดขึ้นกับฉัน แต่เพียงเพื่อการพิจารณาของคุณ

สิ่งนี้อาจทำให้คุณประหลาดใจ แต่คุณสามารถใช้ UIToolbarซึ่งมีเอฟเฟกต์มาตรฐานนั้นอยู่แล้ว (เฉพาะ iOS 7+) ในคุณดู viewDidLoad ของคอนโทรลเลอร์:

self.view.opaque = NO;
self.view.backgroundColor = [UIColor clearColor]; // Be sure in fact that EVERY background in your view's hierarchy is totally or at least partially transparent for a kind effect!

UIToolbar *fakeToolbar = [[UIToolbar alloc] initWithFrame:self.view.bounds];
fakeToolbar.autoresizingMask = self.view.autoresizingMask;
// fakeToolbar.barTintColor = [UIColor white]; // Customize base color to a non-standard one if you wish
[self.view insertSubview:fakeToolbar atIndex:0]; // Place it below everything

1
ใช่มันทำให้ฉันประหลาดใจ ฉันยืนยันแล้วความคิดนี้ใช้งานได้ ฉันเปลี่ยนแค่บรรทัดเดียวในviewDidLoadแบบนี้ - (โมฆะ) viewDidLoad {[super viewDidLoad]; self.view = [[UIToolbar จัดสรร] initWithFrame: CGRectZero]; } ในกรณีของฉันฉันจัดวางมุมมองของฉันโดยใช้โปรแกรม (แบบเก่า) ฉันโหวตให้โซลูชันนี้เนื่องจาก UIToolbar สืบทอด UIView โดยพื้นฐานแล้วฉันไม่เห็นปัญหาใด ๆ ในโซลูชันนี้ ฉันจะทดสอบเพิ่มเติมเมื่อฉันพัฒนาและทดสอบโซลูชันนี้
Ashok

นี่เป็นความคิดที่ดีและดูเหมือนว่าจะได้ผลดีจริงๆ หวังว่าฉันจะสามารถควบคุมได้มากกว่านี้ แต่ก็ดีเท่าที่จะทำได้! ที่กล่าวว่า @SudhirJonathan ได้กล่าวถึงลิงก์ด้านบนซึ่งผู้เขียนจะนำไปสู่อีกระดับ - เขาขโมย CALAYER จาก UIToolBar และนำมาใช้ใหม่! ยอดเยี่ยม!
David H

2
จริงๆ? ในบริเวณใด มันไม่ได้ใช้ API ส่วนตัวใด ๆ และหากวิธีการใหม่ ๆ ในการทำสิ่งต่างๆจะถูกปฏิเสธผลกระทบมากมายก็เป็นไปไม่ได้ ...
TheEye

ทำงานบน iOS 7.1 iPhone ของฉัน
ถึง

มีวิธีที่จะ "ตาย" ความพร่ามัวหรือไม่?
maxisme

13

ตั้งแต่ iOS8 คุณสามารถใช้UIBlurEffect

มี exemples ที่ดีในการมีiOS8SamplerกับUIBlurEffectและUIVibrancyEffect


2
สำหรับคนขี้เกียจ: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
Ric Santos

13

วิธีใหม่ที่ดีที่สุดในการรับภาพซ้อนทับแบบเบลอคือการใช้ฟีเจอร์ใหม่ของ iOS 8 UIVisualEffectView

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

UIVisualEffectView *bluredView = [[UIVisualEffectView alloc] initWithEffect:effect];

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect รองรับรูปแบบสามประเภท มืดแสงและแสงพิเศษ


1

คุณสามารถสร้างคลาสด้วย UIToolBar ที่เป็นคลาสย่อยของ UIView และสร้างอินสแตนซ์ในตัวควบคุมมุมมองแยกต่างหาก วิธีนี้แสดงให้เห็นถึง UIToolBar โปร่งแสง (คลาสย่อยโดย UIView) ที่ให้ข้อเสนอแนะแบบสด (ในกรณีนี้สำหรับ AVCaptureSession)

YourUIView.h

#import <UIKit/UIKit.h>

@interface YourUIView : UIView
@property (nonatomic, strong) UIColor *blurTintColor;
@property (nonatomic, strong) UIToolbar *toolbar;
@end

YourUIView.m

#import "YourUIView.h"

@implementation YourUIView

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    // If we don't clip to bounds the toolbar draws a thin shadow on top
    [self setClipsToBounds:YES];

    if (![self toolbar]) {
        [self setToolbar:[[UIToolbar alloc] initWithFrame:[self bounds]]];
        [self.toolbar setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self insertSubview:[self toolbar] atIndex:0];

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_toolbar]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(_toolbar)]];
    }
}

- (void) setBlurTintColor:(UIColor *)blurTintColor {
    [self.toolbar setBarTintColor:blurTintColor];
}

@end

เมื่อปรับแต่ง UIView ข้างต้นแล้วให้สร้างคลาสที่เป็นคลาสย่อยของ ViewController ด้านล่างนี้ฉันได้สร้างคลาสที่ใช้เซสชัน AVCapture คุณต้องใช้ AVCaptureSession เพื่อที่จะลบล้างการกำหนดค่ากล้องในตัวของ Apple ดังนั้นคุณสามารถซ้อนทับ UIToolBar tranclucent จากคลาสYourUIView

YourViewController.h

#import <UIKit/UIKit.h>

@interface YourViewController : UIViewController
@property (strong, nonatomic) UIView *frameForCapture;
@end

YourViewController.m

#import "YourViewController.h"
#import <AVFoundation/AVFoundation.h>
#import "TestView.h"

@interface YourViewController ()
@property (strong, nonatomic) UIButton *displayToolBar;

@end

@implementation YourViewController


AVCaptureStillImageOutput *stillImageOutput;
AVCaptureSession *session;

- (void) viewWillAppear:(BOOL)animated
{
    session = [[AVCaptureSession alloc] init];
    [session setSessionPreset:AVCaptureSessionPresetPhoto];

    AVCaptureDevice *inputDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:inputDevice error:&error];

    if ([session canAddInput:deviceInput]) {
        [session addInput:deviceInput];
    }

    AVCaptureVideoPreviewLayer *previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    CALayer *rootLayer = [[self view] layer];
    [rootLayer setMasksToBounds:YES];
    CGRect frame = [[UIScreen mainScreen] bounds];

    self.frameForCapture.frame = frame;

    [previewLayer setFrame:frame];

    [rootLayer insertSublayer:previewLayer atIndex:0];

    stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [stillImageOutput setOutputSettings:outputSettings];

    [session addOutput:stillImageOutput];

    [session startRunning];

    [self.navigationController setNavigationBarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}


- (void)viewDidLoad
{
    [super viewDidLoad];

    /* Open button */

    UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 350, self.view.bounds.size.width, 50)];
    [button addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"Open" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    button.backgroundColor = [UIColor greenColor];
    [self.view addSubview:button];

    UIButton *anotherButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, 50)];
    [anotherButton addTarget:self action:@selector(showYourUIView:) forControlEvents:UIControlEventTouchUpInside];
    [anotherButton setTitle:@"Open" forState:UIControlStateNormal];
    [anotherButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
    anotherButton.backgroundColor = [UIColor redColor];
    [self.view addSubview:anotherButton];

}

- (void) showYourUIView:(id) sender
{
    TestView *blurView = [TestView new];
    [blurView setFrame:self.view.bounds];
    [self.view addSubview:blurView];
}


@end

คำตอบดูเหมือนจะไม่เกี่ยวข้องกับคำถามอย่างสิ้นเชิง
combinatorial

@combinatorial นี่เป็นหนึ่งในวิธีที่มีประสิทธิภาพมากขึ้นในการเพิ่มมุมมองโปร่งใสให้กับตัวควบคุมมุมมองอื่น ฉันรวมรหัส AVCapture เพื่อแสดงให้เห็นว่าสามารถใช้สำหรับการตอบรับสดแทนที่จะเพิ่มภาพพื้นหลังที่พร่ามัวตามที่ผู้ใช้รายอื่นแนะนำ
74U n3U7r1no

โอเคขออภัยคุณอาจต้องการเพิ่มบางอย่างในตอนต้นเพื่อสรุปแนวทางและเหตุผลในการใช้
combinatorial

@combinatorial ขอบคุณ
74U n3U7r1no
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.