omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    Welcome!

    This is the community forum for my apps Pythonista and Editorial.

    For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.


    UI gaussian blur

    Pythonista
    6
    17
    9209
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • omz
      omz last edited by

      Below is a little BlurView class I've written to wrap UIVisualEffectView in an easy-to-use ui.View subclass. For the style argument, you can pass 1 (extra light) 2 (light) or 3 (dark). You can also use this class in the UI editor. Simply add a custom view and set its class to BlurView. To set the style from the UI editor, you can put something like {'style': 2} in the "custom attributes" field.

      import ui
      from objc_util import *
      
      class BlurView (ui.View):
      	def __init__(self, style=1, *args, **kwargs):
      		ui.View.__init__(self, **kwargs)
      		self._style = style
      		self.effect_view = None
      		self.setup_effect_view()
      	
      	@on_main_thread
      	def setup_effect_view(self):
      		if self.effect_view is not None:
      			self.effect_view.removeFromSuperview()
      		UIVisualEffectView = ObjCClass('UIVisualEffectView')
      		UIBlurEffect = ObjCClass('UIBlurEffect')
      		frame = (self.bounds[:2], self.bounds[2:])
      		self.effect_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
      		effect = UIBlurEffect.effectWithStyle_(self._style)
      		self.effect_view.effect = effect
      		self.effect_view.setAutoresizingMask_(18)
      		ObjCInstance(self).addSubview_(self.effect_view)
      	
      	@property
      	def style(self):
      		return self._style
      	
      	@style.setter
      	def style(self, value):
      		if value != self._style:
      			self._style = value
      			self.setup_effect_view()
      
      1 Reply Last reply Reply Quote 2
      • Webmaster4o
        Webmaster4o last edited by

        This is awesome! Thanks!

        1 Reply Last reply Reply Quote 1
        • Phuket2
          Phuket2 last edited by

          Ok, I didn't want to be the stupid one to ask this question, but I will. What's the usage of the class. Sorry, I don't get it from the text.
          Do you use create a custom class inheriting from BlurView, or do you add Blur view as a subview to a class?
          Sorry, its probably a silly question,

          1 Reply Last reply Reply Quote 2
          • omz
            omz last edited by

            @Phuket2 Basically, you just create a BlurView instance, and add it on top of the background you want to apply the blur effect on.

            Phuket2 1 Reply Last reply Reply Quote 1
            • Phuket2
              Phuket2 @omz last edited by

              @omz , ok thanks.
              Should it work if you already have a custom class that inherits from ui.View, then you change it to inherit from BlurView instead

              1 Reply Last reply Reply Quote 1
              • omz
                omz last edited by

                @Phuket2 Should be possible, but you must make sure to call BlurView.__init__ in your custom subclass.

                1 Reply Last reply Reply Quote 0
                • blmacbeth
                  blmacbeth last edited by

                  @omz I have been playing around with UIBlurView and UIVibrancyEffect, but have not been able to get the UIVibrancyEffect to work (text does not show up). Any suggestions on how to get it to work? I'm away from my iPad right now and can post some code later, if needed. But, my code is based on the following Objective-C code:

                  // Blur effect
                  UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
                  UIVisualEffectView *blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
                  [blurEffectView setFrame:self.view.bounds];
                  [self.view addSubview:blurEffectView];
                  
                  // Vibrancy effect
                  UIVibrancyEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:blurEffect];
                  UIVisualEffectView *vibrancyEffectView = [[UIVisualEffectView alloc] initWithEffect:vibrancyEffect];
                  [vibrancyEffectView setFrame:self.view.bounds];
                  
                  // Label for vibrant text
                  UILabel *vibrantLabel = [[UILabel alloc] init];
                  [vibrantLabel setText:@"Vibrant"];
                  [vibrantLabel setFont:[UIFont systemFontOfSize:72.0f]];
                  [vibrantLabel sizeToFit];
                  [vibrantLabel setCenter: self.view.center];
                  
                  // Add label to the vibrancy view
                  [[vibrancyEffectView contentView] addSubview:vibrantLabel];
                  
                  // Add the vibrancy view to the blur view
                  [[blurEffectView contentView] addSubview:vibrancyEffectView];
                  

                  Thanks,
                  B

                  1 Reply Last reply Reply Quote 1
                  • omz
                    omz last edited by

                    @blmacbeth Here's an extended version of BlurView that includes support for vibrancy effects. The main function shows a little demo.

                    # coding: utf-8
                    
                    import ui
                    from objc_util import *
                    
                    class BlurView (ui.View):
                    	def __init__(self, style=1, *args, **kwargs):
                    		ui.View.__init__(self, **kwargs)
                    		self._style = style
                    		self.effect_view = None
                    		self.setup_effect_view()
                    	
                    	@on_main_thread
                    	def setup_effect_view(self):
                    		if self.effect_view is not None:
                    			self.effect_view.removeFromSuperview()
                    		UIVisualEffectView = ObjCClass('UIVisualEffectView')
                    		UIVibrancyEffect = ObjCClass('UIVibrancyEffect')
                    		UIBlurEffect = ObjCClass('UIBlurEffect')
                    		UILabel = ObjCClass('UILabel')
                    		frame = (self.bounds[:2], self.bounds[2:])
                    		self.effect_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
                    		effect = UIBlurEffect.effectWithStyle_(self._style)
                    		self.effect_view.effect = effect
                    		self.effect_view.setAutoresizingMask_(18)
                    		ObjCInstance(self).addSubview_(self.effect_view)
                    		vibrancy_effect = UIVibrancyEffect.effectForBlurEffect_(effect)
                    		self.vibrancy_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
                    		self.vibrancy_view.effect = vibrancy_effect
                    		self.effect_view.contentView().addSubview_(self.vibrancy_view)
                    		
                    	@property
                    	def style(self):
                    		return self._style
                    	
                    	@style.setter
                    	def style(self, value):
                    		if value != self._style:
                    			self._style = value
                    			self.setup_effect_view()
                    	
                    	@on_main_thread
                    	def add_vibrant_label(self, label):
                    		self.vibrancy_view.contentView().addSubview_(ObjCInstance(label))
                    
                    def main():
                    	image_view = ui.ImageView(frame=(0, 0, 320, 320))
                    	image_view.image = ui.Image.named('test:Mandrill')
                    	blur_view = BlurView(style=2, frame=image_view.bounds.inset(40, 40))
                    	image_view.add_subview(blur_view)
                    	label = ui.Label(frame=blur_view.bounds)
                    	label.text = 'Hello World'
                    	label.font = ('HelveticaNeue', 40)
                    	label.alignment = ui.ALIGN_CENTER
                    	blur_view.add_vibrant_label(label)
                    	image_view.present('sheet')
                    
                    main()
                    
                    1 Reply Last reply Reply Quote 2
                    • blmacbeth
                      blmacbeth last edited by

                      @omz You're the man! Thanks for that.

                      1 Reply Last reply Reply Quote 1
                      • blmacbeth
                        blmacbeth last edited by

                        Noticed some bugs in the above code, so here are my fixes to make it work (in Pythonista3, at least).

                        # coding: utf-8
                        
                        import ui
                        from objc_util import *
                        
                        class BlurView (ui.View):
                            def __init__(self, style=1, *args, **kwargs):
                                ui.View.__init__(self, **kwargs)
                                self._style = style
                                self.effect_view = None
                                self.setup_effect_view()
                            
                            @on_main_thread
                            def setup_effect_view(self):
                                if self.effect_view is not None:
                                    self.effect_view.removeFromSuperview()
                                UIVisualEffectView = ObjCClass('UIVisualEffectView')
                                UIVibrancyEffect = ObjCClass('UIVibrancyEffect')
                                UIBlurEffect = ObjCClass('UIBlurEffect')
                                UILabel = ObjCClass('UILabel')
                                # Brooks patch for Rect not having a 'slice' 
                                bounds = self.bounds.as_tuple()
                                frame = (bounds[:2], bounds[2:])
                                self.effect_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
                                effect = UIBlurEffect.effectWithStyle_(self._style)
                                self.effect_view.effect = effect
                                self.effect_view.setAutoresizingMask_(18)
                                ObjCInstance(self).addSubview_(self.effect_view)
                                vibrancy_effect = UIVibrancyEffect.effectForBlurEffect_(effect)
                                self.vibrancy_view = UIVisualEffectView.alloc().initWithFrame_(frame).autorelease()
                                self.vibrancy_view.effect = vibrancy_effect
                                self.effect_view.contentView().addSubview_(self.vibrancy_view)
                                
                            @property
                            def style(self):
                                return self._style
                            
                            @style.setter
                            def style(self, value):
                                if value != self._style:
                                    self._style = value
                                    self.setup_effect_view()
                            
                            # Brooks fix @on_mains_thread to @on_main_thread
                            @on_main_thread
                            def add_vibrant_label(self, label):
                                self.vibrancy_view.contentView().addSubview_(ObjCInstance(label))
                        
                        def main():
                            image_view = ui.ImageView(frame=(0, 0, 320, 320))
                            image_view.image = ui.Image.named('test:Mandrill')
                            blur_view = BlurView(style=2, frame=image_view.bounds.inset(40, 40))
                            image_view.add_subview(blur_view)
                            label = ui.Label(frame=blur_view.bounds)
                            label.text = 'Hello World'
                            label.font = ('HelveticaNeue', 40)
                            label.alignment = ui.ALIGN_CENTER
                            blur_view.add_vibrant_label(label)
                            image_view.present('sheet')
                        
                        main()
                        

                        The biggest problem was that the ui.Rect() object does not have the ability to use slices. This was fixed with the ui.Rect().as_tuple() function. The second problem was just a typo.

                        B

                        1 Reply Last reply Reply Quote 1
                        • rb
                          rb last edited by

                          How could you apply the vibrancy effect to work with a rectangular region rather than a label? I read there is a fill method and a separator method but not sure how you would implement.

                          cvp 1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp @rb last edited by

                            @rb What do you call a rectangular region? A label could be seen as a rectangular region if you don't set its text.

                            1 Reply Last reply Reply Quote 0
                            • rb
                              rb last edited by

                              Ah ok - so what is the difference then between fill and label?I just thought label would be isolated to text - but it I’ll try that!

                              cvp 1 Reply Last reply Reply Quote 0
                              • cvp
                                cvp @rb last edited by

                                @rb the blur_view it-self is a rectangular region, thus no need of label at all

                                def main():
                                    image_view = ui.ImageView(frame=(0, 0, 320, 320))
                                    image_view.image = ui.Image.named('test:Mandrill')
                                    blur_view = BlurView(style=16, frame=image_view.bounds.inset(40, 40))
                                    image_view.add_subview(blur_view)
                                    #label = ui.Label(frame=blur_view.bounds)
                                    #label.text = 'Hello World'
                                    #label.font = ('HelveticaNeue', 40)
                                    #label.alignment = ui.ALIGN_CENTER
                                    #blur_view.add_vibrant_label(label)
                                    image_view.present('sheet')
                                
                                1 Reply Last reply Reply Quote 0
                                • rb
                                  rb last edited by

                                  No I mentioned vibrancy- ie I want bg to be blurred but a central rectangle to be not blurred and more vibrant.

                                  cvp 1 Reply Last reply Reply Quote 0
                                  • cvp
                                    cvp @rb last edited by

                                    @rb ok, sorry, misunderstood

                                    1 Reply Last reply Reply Quote 0
                                    • First post
                                      Last post
                                    Powered by NodeBB Forums | Contributors