Tampilan Blur gaya iOS 7

113

Apakah ada yang tahu tentang kontrol yang akan meniru tampilan blur gaya iOS7.

Saya berasumsi bahwa mungkin ada semacam subkelas UIView yang akan meniru perilaku tersebut.

Saya berbicara tentang jenis tampilan yang memburamkan latar belakang dengan sangat tebal sehingga memiliki efek tarik dari tampilan latar belakang.

masukkan deskripsi gambar di sini

endy
sumber
6
GPUImage mungkin membantu.
Maarten
@Anil baik maka pertanyaannya adalah ketika ios7 SDK dirilis bagaimana saya bisa melakukan ini tanpa membatasi aplikasi saya hanya untuk ios7;).
berakhir
1
Apple telah merilis kategori UIImage yang melakukan hal ini. Hanya mencoba menemukannya.
Fogmeister
1
Kode ini ditautkan dari sesi WWDC 201. Ini publik di github, saya tidak bisa menemukannya atm.
Fogmeister

Jawaban:

40

Anda mungkin dapat memodifikasi sesuatu seperti RWBlurPopover Bin Zhang untuk melakukan ini. Komponen itu menggunakan GPUImage saya untuk menerapkan Gaussian blur ke komponen di bawahnya, tetapi Anda dapat dengan mudah menggunakan CIGaussianBlur untuk hal yang sama. GPUImage mungkin lebih cepat .

Komponen tersebut bergantung pada kemampuan Anda untuk menangkap tampilan di balik tampilan yang Anda sajikan, dan mungkin mengalami masalah dengan tampilan yang bergerak di balik konten ini. Kebutuhan untuk melakukan perjalanan melalui Core Graphics untuk meraster tampilan latar belakang akan memperlambat segalanya, jadi kami mungkin tidak memiliki akses langsung yang memadai untuk dapat melakukan ini dengan cara yang baik untuk overlay pada tampilan animasi.

Sebagai pembaruan di atas, saya baru-baru ini mengerjakan ulang blur di GPUImage untuk mendukung radius variabel, memungkinkan replikasi lengkap ukuran blur di tampilan pusat kendali iOS 7. Dari situ, saya membuat kelas GPUImageiOS7BlurFilter yang merangkum ukuran blur yang tepat dan koreksi warna yang tampaknya digunakan Apple di sini. Beginilah perbandingan blur GPUImage (di kanan) dengan blur bawaan (di kiri):

Keburaman Apple GPUImage buram

Saya menggunakan 4X downsampling / upsampling untuk mengurangi jumlah piksel yang harus dioperasikan oleh Gaussian blur, sehingga iPhone 4S dapat memburamkan seluruh layar dalam waktu sekitar 30 ms menggunakan operasi ini.

Anda masih memiliki tantangan tentang cara menarik konten ke dalam keburaman ini dari pandangan di belakang yang satu ini dengan cara yang baik.

Brad Larson
sumber
Jadi, bagaimana menurut Anda Apple berhasil melakukannya? Jika Anda membuka aplikasi Kamera, dan menarik Pusat Kontrol (layar pengaturan dari bawah), keburaman mengikuti apa yang dilihat Kamera.
Snowman
2
@maq - Memiliki akses tersembunyi ke semua yang ada di sistem sangat membantu. Apa yang dapat dilakukan seseorang yang mengembangkan OS sangat berbeda dari apa yang dapat dilakukan oleh antarmuka publik.
Brad Larson
3
@maq - Kamera memberi umpan secara khusus, ya. Salah satu cara untuk melakukan ini adalah dengan menggunakan GPUImage untuk menarik bingkai kamera (melalui AV Foundation) dan kemudian memiliki output tersebut ke GPUImageView untuk output kamera langsung dan kemudian secara paralel dimasukkan ke dalam gaussian blur (dan mungkin crop untuk mencocokkan posisi tampilan yang diburamkan) dan keluaran tersebut ke GPUImageView lain yang akan menampilkan konten yang diburamkan di belakang kontrol Anda. Itu dimungkinkan karena kami memiliki jalur cepat dari bingkai kamera ke OpenGL ES, tetapi kami tidak memiliki hal serupa untuk elemen UI generik.
Brad Larson
1
Saya mengambil tangkapan layar UIView secara terprogram dan menggunakan GPUImageGaussianBlurFilter untuk mencoba membuat efek serupa, tetapi hasilnya sangat berbeda dari gaya Apple. Filter tampaknya kabur dalam kisi, dengan kotak terlihat di mana-mana, di mana Apple hanyalah satu lembar halus.
Snowman
1
@maq - Pastikan Anda menggunakan kode terbaru dari repositori, karena sebelumnya ada bug pada radius buram tinggi. Konon, blur hanya mengambil sampel area 9-piksel secara default, jadi jika Anda meningkatkan pengali untuk blur melewati titik itu, Anda akan mulai melihat artefak dari melewatkan piksel. Ini dilakukan karena alasan performa, tetapi Anda dapat memodifikasi vertex dan shader fragmen untuk mengambil sampel piksel dalam jumlah yang lebih besar. Itu, atau coba terapkan CIGaussianBlur, yang memiliki implementasi blur yang lebih umum. Suatu hari, saya akan memperluas keburaman ini ke radius yang lebih besar.
Brad Larson
28

Saya menggunakan FXBlurViewyang berfungsi dengan baik di 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]

Saya menambahkannya dengan menggunakan:

FXBlurView *blurView = [[FXBlurView alloc] initWithFrame:CGRectMake(50, 50, 150, 150)];
[self.blurView setDynamic:YES];
[self.view addSubview:self.blurView];
Paul Peelen
sumber
2
Apakah ada trik untuk menggunakan FXBlurView? Saya sudah mencobanya, tetapi kami menghasilkan tampilan yang lamban pada iPhone 5. Proyek demo mereka berfungsi dengan baik. Cukup aneh.
Cris
Itu tergantung pada apa yang ingin Anda lakukan. Ketika saya meletakkan FXBlurViewdi atas a UIScrollViewsaya juga mendapat hasil yang lamban. Saya yakin ini ada hubungannya dengan cara menambahkan blur. Apple, jika saya tidak salah, langsung mengakses GPU saat menggunakan blurnya sendiri, yang tidak dapat kami lakukan sebagai pengembang. Karenanya, solusi @cprcrack sebenarnya adalah solusi terbaik di sini.
Paul Peelen
2
Bagaimana Anda menangani rotasi perangkat dengan FXBlurView? Saya sedang mempresentasikan dialog modal saat ini; dialog itu sendiri berputar dengan baik tetapi latar belakangnya dipadatkan dengan cara yang salah (pada dasarnya perlu diperbarui setelah rotasi).
fatuhoku
1
Tentu saja, FXBlurView adalah pilihan yang bagus, tetapi jika ada masalah penggunaan CPU. daripada saya lebih suka blurView lainnya. saya menggunakan ini di UICollectionVIew dan UITableView tetapi meningkatkan penggunaan CPU saya. dalam menjalankan berikutnya saya mengomentari alokasi tersebut dan itu menjadi normal. Saya harap, ini akan membantu seseorang.
Vatsal Shukla
27

PERINGATAN: seseorang di komentar menyatakan bahwa Apple menolak aplikasi menggunakan teknik ini. Itu TIDAK terjadi pada saya, tetapi hanya untuk pertimbangan Anda.

Ini mungkin mengejutkan Anda, tetapi Anda dapat menggunakan UIToolbar , yang sudah menyertakan efek standar tersebut (hanya iOS 7+). Dalam Anda melihat viewDidLoad pengontrol:

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
cprcrack
sumber
1
Ya, itu mengejutkan saya. Saya memverifikasi, ide ini berhasil. Saya hanya membuat satu perubahan baris viewDidLoadseperti ini. - (void) viewDidLoad {[super viewDidLoad]; self.view = [[UIToolbar alokasi] initWithFrame: CGRectZero]; } Dalam kasus saya, saya mengatur tampilan saya secara terprogram (gaya lama). Saya memberikan suara positif untuk solusi ini karena UIToolbar mewarisi UIView sehingga pada dasarnya saya tidak melihat masalah apa pun dalam solusi ini. Saya akan menguji lebih banyak saat saya mengikuti pengembangan & menguji solusi ini.
Ashok
Ini adalah ide yang bagus dan tampaknya bekerja dengan sangat baik. Seandainya saya memiliki lebih banyak kendali, tetapi ini sebagus yang didapat! Yang mengatakan, @SudhirJonathan menyebutkan tautan di atas di mana penulis membawa ini ke tingkat berikutnya - DIA MENCURI CALAYER dari UIToolBar dan menggunakannya kembali! Cemerlang!
David H
2
Betulkah? Atas dasar apa? Itu tidak menggunakan API pribadi apa pun, dan jika semua cara inovatif untuk melakukan sesuatu ditolak, banyak efek tidak akan mungkin ...
TheEye
Bekerja pada iPhone iOS 7.1 saya
marsant
Apakah ada cara untuk "meredakan" kekaburan?
maxisme
13

Sejak iOS8, Anda dapat menggunakan UIBlurEffect .

Ada contoh bagus di iOS8Sampler dengan UIBlurEffect dan UIVibrancyEffect .

VivienCormier
sumber
2
Untuk pemalas: UIVisualEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; UIVisualEffectView *blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
Ric Santos
13

Cara baru terbaik untuk mendapatkan Overlay yang kabur adalah dengan menggunakan Fitur baru iOS 8 UIVisualEffectView.

UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

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

bluredView.frame = self.view.bounds;

[self.view addSubview:bluredView];

UIBlurEffect mendukung tiga jenis Style. Gelap, Terang, dan Cahaya Ekstra.

Jeanette Müller
sumber
1

Anda dapat membuat kelas dengan UIToolBar yang merupakan subkelas dari UIView dan membuat instance di pengontrol tampilan terpisah. Pendekatan ini mendemonstrasikan UIToolBar tembus pandang (disubkelas oleh UIView) yang memberikan umpan balik langsung (dalam hal ini untuk 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

Setelah UIView di atas telah disesuaikan, lanjutkan dan buat kelas yang merupakan subkelas dari ViewController. Di bawah ini saya telah membuat kelas yang menggunakan sesi AVCapture. Anda harus menggunakan AVCaptureSession untuk mengganti konfigurasi kamera bawaan Apple. Dengan demikian Anda dapat melapisi UIToolBar tranclucent dari kelas 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
74U n3U7r1no
sumber
Jawabannya sepertinya sama sekali tidak berhubungan dengan pertanyaan itu.
kombinatorial
@combinatorial Ini adalah salah satu cara yang lebih efisien untuk menambahkan tampilan transparan ke pengontrol tampilan lain. Saya menyertakan kode AVCapture untuk menunjukkan bahwa itu dapat digunakan untuk umpan balik langsung daripada hanya menambahkan gambar latar belakang buram, seperti yang direkomendasikan pengguna lain.
74U n3U7r1no
Oke, maaf, Anda mungkin ingin menambahkan sesuatu di awal yang merangkum pendekatan dan alasan menggunakannya.
kombinatorial
@combinatorial Terima kasih
74U n3U7r1no