Fade UIImageView as it approaches the edges of a UIScrollView - ios

I have a UIScrollView over an image at the bottom of my app that acts as a dock with icons that can be scrolled through horizontally. Instead of the harsh edges of the UIScrollView, I would like the icons to fade out for a more aesthetically pleasing look. Being new to iOS development, I don't know if either of these would be valid options:
Create a faded image to use as an overlay on the scrollview so the
icons only appear through the visible portion.
Actually change the
alpha of the images based on their distance from the center (or from
each edge).
I suspect the first idea would be the most simple, but I'd like to throw this out there for any other ideas.
Note: I did see this tutorial, however that technique assumes that the background is a solid color. If I were to do it programatically, I would probably need to fade the individual images.

You can definitely implement something along the lines of #2. It'd be something similar to what the tutorial describes. The alpha transition however won't be as smooth as using the gradient layer mentioned in the tutorial or using an image since the entire icon would have the same alpha. How much discernible the difference is depends on the size of your icons. Smaller icons, very few will be able to tell the difference. Larger icons the difference would be quite clear.
You'd have to implement the
(void)scrollViewDidScroll:(UIScrollView *)scrollView
method in your scroll view's delegate class. This method will get called every time the scroll view changes the location of its content. In this method you can call its subviews and adjust their alphas as required. To optimize it a bit instead of calling the alpha adjustments on all the elements you can just update the subviews which are still partially/completely visible.
EDIT: to figure out which views to adjust you'll use the contentOffset property of the scrollView that gets passed as a parameter in the above method.

Related

How to fil rectangular ares in the screen with good performance in ios

I'm making simple number coloring game (like sandbox, pixel art, unicorn, etc) and came across a problem. I tried various methods of filling rects in the screen.
At first i created a backgroundView(a simple UIView) which had 2500 subviews(also UIViews), each one had size = (CGSize){50,50}. Added a tap gesture recognizer, detected which view should be filled, and simply changed the background color of that view. But when i placed the backgroundView in the scrollView, the scroll and zooming were awful.
Tried same thing but this time each rectangle was a CALayer. So a backgroundView, which had 2500 sublayers(each was a CALayer with 50,50 size) - zoom and scroll was also awful.
Tired to use custom drawing with overriding drawRect method in UIView subclass or drawInContext in CALayer subclass(i was filling rects with CGContext), this time problem was also caused by the zooming and scrolling. Because i needed to update every rect when user zooms, it was triggering a lot of drawRect calls, and performance was also bad.
Any thoughts how can i fill rects in the screen ?
Explanation
Yup! Adding 2,500 tiny UIViews to a scroll view can destroy performance. I wouldn't use that approach, but if you do, at least make sure that subview_N.opaque = YES; on all subviews to disable compositing.
The CALayer approach that you described is basically the same as the UIView approach because views are backed by CoreAnimation layers (see -[UIView layer]).
The best options for drawing thousands of rectangles to the screen on iOS without decimating frame rate, is to use one of the following approaches:
Draw directly using CoreGraphics
Draw directly using OpenGL (extremely involved)
Use a layout engine such as UICollectionViewLayout
Now, you said you had tried overriding -[UIView drawRect:], but you didn't provide any example code for us to checkout. Please update your question with actual code for method #3 if you want more specific feedback. It's very likely that something is wrong with the drawRect code you created. CoreGraphics can definitely draw thousands of squares on screen without dragging frame rate down that badly.
One Solution
I recently released a project, YMTreeMap, that draws thousands of rectangles into a UIView to create financial TreeMaps. It's in Swift, not Objective-C, but the underlying concepts are the same. For this, I created a custom UICollectionViewLayout that lets Apple's well tested UICollectionView class handle the nitty gritty of selective drawing, zooming and animation.
The example UIViewController code in the YMTreeMap project shows how to draw thousands of colored rectangles to the screen if all you know is their location and size. This sounds like what you are doing. Since you're also scrolling and zooming, this solution might be perfect for you because UICollectionView has native support for both of those.

Swift: make UIScrollView have a "going out of focus" effect

I'd like to know which library/object/function I should refer to to be able to make my scroll views have that nice out of focus effect. For example make the image coming on screen look smaller as it goes away and blur it at the same time.
My scroll view contains ImageViews that take up the entire bounds of the scroll view.
Blur
For iOS 8+, you can use UIVisualEffectView to achieve this effect. This is a native API that has been fine tuned for performance and great battery life, and it's easy to implement. Alternatively you can check out GPUImageGaussianBlurFilter as described here.
Scale
Check out transform property of the UIView. Using CGAffineTransformMakeScale you can change the scale. Read this very informative blog post about transformations.

iOS segmented control with a little triangle on top

How can I draw a little triangle above the selected item in a UISegmentedControl? Does anyone know an open-source than extends it?
(if not - pointers of how to do it)
Design should look like (this is in the bottom of the screen)
I don't believe there's a native way to do that. You can either find a library that allows for it, but you can do it yourself fairly easily, which I recommend.
I can think of a few out of the box ways to approach it, here at the two I think worth mentioning off the bat:
1) Use UISegmentedControl with images. Make the segmented controller have a height that includes the triangle, and have an image for selected and normal states that shows what you want. The Normal states would have a rectangle of transparency on top, as wide as the entire image and as tall as the triangle. The selected image would include the triangle. Both images should end up the same width and height.
2) Subclass UISegmentedControl and do some custom drawing in drawRect:. You could draw the triangle outside (above) the bounds of the segmented controller, make sure to set the segmented controller's clipToBounds property to NO, as well as its layer's masksToBounds property.
If you'd like more help, or some other suggestions, just ask.

Want a UIVisualEffectView affected by content above as well as below it?

I have a UIVisualEffectView with a UIBlurEffect effect as a pinned UICollectionViewCell in a UICollectionView.
The blur is masked with an icon so that the icon appears in a subtle shimmery way, responding to whatever it is drawn on top of.
The effect is on top of the collection's background. As it stays pinned and the varying background scrolls underneath, it gently changes to reflect the background and looks very nice.
However, except for the collections's scrolling background, most content is drawn in front of the blur effect. This is necessary because that other content is more important and shouldn't be obscured.
Even though it is behind the more important content, I'd like the effect view to reflect the content that is scrolling in front of it. Any suggestions for how this might be made to work?
Ideas:
Could I grab a chunk from the previously drawn frame and draw this under the effect view? How would I do that?
Could I render the whole collection view, apply the blur, and then render everything that should be on top of the blur a second time? How can I make that efficient?!
Thanks.
I went with a slightly refined version of the second option.
I added some duplicate cells to the collection view that are rendered behind the blur, and then also in front. I've only done this for one of my cell types with lots of colour in it. It works pretty well.
If you have a better approach I'll happily assign you the correct answer.

Is there a way to set different frame sizes for different layers in a UIScrollView?

Right now I have a UIScrollView and a semi-transparent top and bottom bar which go over it. The UIScrollView contains a large UIImageView that is pannable and zoomable.
I want to be able to toggle the image and darken everything around a certain part of the image, but have the transparency mesh perfectly with the top/bottom bars which are semi-transparent. Since the content is scrollable/zoomable, if I darken the image itself, anytime that part goes under the top/bottom bars it will double darken.
I tried to solve this dilemma by creating a smaller UIScrollView that sits nested between the top and bottom bars, and sending zoom/pan commands to it in an attempt to mirror the UIScrollView below it, but that didn't work too nicely. It was a nightmare trying to sync the animations (I tried copying over the zoomScale/contentOffset in zoomDidScroll, sending the zoom/pan animation to each UIScrollView individually, using KVO, etc).
Is there any way I can set different frame sizes/cut-off points for each individual layer? Or perhaps each UIImageView subview? I'm open to any other proposed solutions as well, this has really been driving me up the wall. I appreciate the help.
What it's like before toggle:
What I want after toggle:
Why not cover the "center" part with another semi-transparent view to match the tool bars, then use a mask on the layer to make the part of it you wish fully transparent?

Resources