Anti-aliasing issues in UITextField with Blur and Vibrancy Effect

You probably know these days when you end up spending quite a lot of time fixing a small detail. At times you just feel like giving up and taking another direction.

But I really wanted to use the new UIBlurEffect and UIVibrancyEffect tricks in iOS 8 on the login screen for Høst. A couple of days ago, I wrote about smooth transitioning from LaunchImage, but what I didn't include then was the blur and vibrancy effects.

I added that now, and it looks good (IMHO), especially when tapping the button, you'll see the beauty of the vibrancy effect:
UIButton with UIVibrancyEffect

BTW, the button is the awesome AYVibrantButton

But truth be told, there's quite a few issues adding UITextFields to a view with blur and vibrancy effects. For starters, when running in the simulator you cannot see the text:

UIVibrancyEffect in iOS simulator causes text to be invisible

Then I tried running it on a device (iPhone 6), and now the text was visible - but now anti-aliasing was causing troubles:

Fuzzy anti-aliasing in UITextField

And that's when it started to get "interessting". Was it because of everything being inside a ScrollView? Was it because the background color of the textfield was at 0.3 alpha? Oh no, is this due to franctional frame coordinates? But I use Auto Layout?!?!?

I tried everything. Even hardcoding frames, instead of using Auto Layout (from code, not Interface Builder). I also moved the textfield outside, and above the effect views just to see I wasn't going crazy - and sure enough anti-aliasing worked as it should when placed outside the effect views.

Then I tried playing around with the text color. I figured that since the background color of the textfield was white, and the text color was black - it ought to anti-alias the edges with white.

First of all, I changed the background color to a light gray: passwordTextField.backgroundColor = UIColor(red:0.67, green:0.67, blue:0.67, alpha:1) and left the text color the same:

Very safe password

Not much better! After all, the background doesn't seem to have influence on anti-aliasing at all. The white fuzziness looks pretty much the same as before.

So let's try changing the text color to something close to black, but not black: passwordTextField.textColor = UIColor(red:0.15, green:0.15, blue:0.15, alpha:1)

Prettier, Very safe password

Now that looks a lot better. I tried playing around with the colors, and in terms of black I didn't get a desireable result with less than 0.1 for red, green and blue.

Looking at the screenshot, notice the darker blur behind the username text field. This kinda explains it all to me; When I used the color UIColor(red:0.09, green:0.09, blue:0.09, alpha:1) it looked fine before the darker area, but within the darker area, it was still fuzzy:

0.09 and still fuzzy

So it might be about time to understand exactly what the UIVibrancyEffect does, so let's look at the documentation:

A UIVibrancyEffect object amplifies and adjusts the color of the content layered behind a UIVisualEffectView object, allowing the content placed inside of the contentView to become more vivid.

So it ultimately adjusts the colors of the UITextField to become more vivid. Then try to click the More link in the documentation and see what it says:

The vibrancy effect is color dependent. Any subviews that you add to the contentView must implement the tintColorDidChange method and update themselves accordingly.

Maybe that would help? To adjust the textColor when the vibrancy effect changes the tintColor? I already used a subclass of UITextField so I added this:

override func tintColorDidChange() {  
    self.textColor = self.tintColor

And sure enough, it adjust the text color to fix anti-aliasing - of course that leaves us with little control over the text color - but that's what we kind of ask for when using the UIVibrancyEffect.

Adjusting textColor when tintColor changes

I might need to adjust the font, to make it a little more readable - but nevermind for now.

Just for a little while I thought that this would also fix the invisible text when running the app in the simulartor - but apparently my expectations were too high...