how to designed a specific shape of scrollView - ios

How iOS we can to achieve a specific shape of the scrollView, the system provides graphical shape of scrollView.
I want to achieve scrollView in a hexagonal or circular shape, Is there some design ideas?

Just do like this:
CAShapeLayer *layer = [CAShapeLayer layer];
// self is the scroll view
layer.frame = self.bounds;
// here is a circular arc
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius:self.bounds.size.width / 2.5 startAngle:-3 / 4 * M_PI endAngle:1 / 3 * M_PI clockwise:YES];
layer.lineWidth = 20;
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor blackColor].CGColor;
layer.lineCap = kCALineCapRound;
self.layer.mask = layer;
self.layer.masksToBounds = YES;

Related

How to draw shadow around the masked UIView?

I want to make a UIView which will have shape like in Figure 1. and also should have shadow around the shape of my view .
I am using below code to draw CAShaperLayer with UIBezierPath
UIBezierPath *bezier = [UIBezierPath bezierPath];
[bezier moveToPoint:CGPointMake(0,7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-15, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-10,0)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width-5, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width, 7)];
[bezier addLineToPoint:CGPointMake(self.menuView.frame.size.width, self.menuView.frame.size.height)];
[bezier addLineToPoint:CGPointMake(0, self.menuView.frame.size.height)];
[bezier closePath];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.path = [bezier CGPath];
self.menuView.layer.mask = maskLayer;
and for adding shadow
self.menuView.layer.shadowColor = [[UIColor colorWithRed:8.0f/255.0f green:37.0f/255.0f blue:82.0f/225.0f alpha:1] CGColor];
self.menuView.layer.shadowOffset = CGSizeZero;
self.menuView.layer.shadowOpacity = 0.3f;
self.menuView.layer.shadowRadius = 5.0f;
self.menuView.layer.masksToBounds=NO;
My Problem :
After masking CAShaperLayer on menuView ,the shadow has disappeared . Figure 2
Instead of Masking View , i also tried to add Sublayer on it
[self.menuView.layer addSublayer:maskLayer]
but this will hide my all SubViews of MenuView Figure 3
(I have changed the CASahperLayer Color to Black just to show )
🔹 My Question is :
What is the best way to get the perfect shape with shadow as shown in Figure 1 ???.
(Thanks in advance)
extension UIView{
func viewShadowBorder() {
self.layer.shadowColor = UIColor.gray.cgColor
self.layer.shadowOpacity = 1
self.layer.shadowOffset = CGSize.zero
self.layer.shadowRadius = 2
self.layer.cornerRadius = 2
}
}

Creating a transparent hole on UIVisualEffect view

I'm trying to create a transparent hole kind of view on the UIVisualEffectView. I was following the solution given here. I have attached my sample code which I worked on here. I'm trying to create a transparent view whose frame is taken from the image view behind the blurry view. Anyone could tell me what is that I'm doing wrong here?
You can use a UIBezierPath to create the mask you want.
blurView.layer.mask = ({
CGRect roundedRect = self.bounds;
roundedRect.origin.x = roundedRect.size.width / 4.0f;
roundedRect.origin.y = roundedRect.size.height / 4.0f;
roundedRect.size.width /= 2.0f;
roundedRect.size.height /= 2.0f;
CGFloat cornerRadius = roundedRect.size.height / 2.0f;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.bounds];
UIBezierPath *croppedPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:cornerRadius];
[path appendPath:croppedPath];
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.path = path.CGPath;
mask.fillRule = kCAFillRuleEvenOdd;
mask;
});
Swift 5 version of the solution for lazy ones :)
var roundedRect = visualEffectsView.bounds
roundedRect.origin.x = roundedRect.size.width / 4
roundedRect.origin.y = roundedRect.size.height / 4
roundedRect.size.width = roundedRect.size.width / 2
roundedRect.size.height = roundedRect.size.height / 2
let cornerRadius = roundedRect.size.height / 2
let path = UIBezierPath(rect: visualEffectsView.bounds)
let croppedPath = UIBezierPath(roundedRect: roundedRect, cornerRadius: cornerRadius)
path.append(croppedPath)
path.usesEvenOddFillRule = true
let mask = CAShapeLayer()
mask.path = path.cgPath
mask.fillRule = .evenOdd
visualEffectsView.layer.mask = mask

draw a circular progress view which shows range

A circular view will show progress as you can see I have pointed out, the circular view should be divided in ranges and will show a progress how much percent is reached.
I don't know how to approach with this design and how to divide the view in equal range and shows how much progress user has achieved.
Any suggestion and help will be appreciated.
Thanks
Use two CAShapeLayer,one as background,one as progress
Example
-(CAShapeLayer *)createCircleWithBounds:(CGRect)bounds
Position:(CGPoint)position
StrokeColor:(UIColor*)color
LineWidth:(CGFloat)lineWidth
{
CAShapeLayer* shapelayer = [CAShapeLayer layer];
shapelayer.strokeColor = color.CGColor;
shapelayer.fillColor = [UIColor clearColor].CGColor;
shapelayer.path = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:CGRectGetWidth(bounds)/2].CGPath;
shapelayer.bounds = bounds;
shapelayer.position = position;
shapelayer.lineCap = kCALineCapButt;
shapelayer.lineWidth = lineWidth;
return shapelayer;
}
Then
CAShapeLayer * progressLayer = [self createCircleWithBounds:CGRectMake(0, 0, 100, 100) Position:self.view.center StrokeColor:[UIColor whiteColor] LineWidth:5.0];
progressLayer.strokeStart = 0.2;
progressLayer.strokeEnd = 0.8;
[self.view.layer addSublayer:progressLayer];
CAShapeLayer * otherLayer = [self createCircleWithBounds:CGRectMake(0, 0, 100, 100) Position:self.view.center StrokeColor:[UIColor blueColor] LineWidth:5.0];
otherLayer.strokeStart = 0.2;
otherLayer.strokeEnd = 0.5;
[self.view.layer addSublayer:otherLayer];
Then what you need to do is just use some math function to change the otherLayer.strokeEnd when the progress change
You can use CAShapeLayer and CGPath to programatically draw it.

Cutting a layer out of a layer

So I'm trying to cut a circle out of an existing layer; and here's my code:
CGRect bounds = _containerLayer.bounds;
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.fillColor = [UIColor blackColor].CGColor;
CGFloat smallCircleRadius = (frame.size.width - barWidth)/2;
CGRect smallCircleRect = CGRectMake(CGRectGetMidX(bounds) - smallCircleRadius, CGRectGetMidY(bounds) - smallCircleRadius, 2 * smallCircleRadius, 2 * smallCircleRadius);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:smallCircleRect];
[circlePath appendPath:[UIBezierPath bezierPathWithRect:bounds]];
maskLayer.path = circlePath.CGPath;
maskLayer.fillRule = kCAFillRuleEvenOdd;
_containerLayer.mask = maskLayer;
This code does work, as I now see a black rectangle with a hollow circle in the middle. But the problem is that when I tried to set maskLayer.fillColor = [UIColor clearColor].CGColor;, The whole thing including _containerLayer just disappears - I want to make the fillColor transparent so I can see what's originally in the _containerLayer (which wasn't cut out). What should I do to achieve this? Thanks!

lineWidth for UIBezierPath has maximum

I'm trying to create an arc, like a half circle, that i can animate with different colors. I thought I would start with creating a bezier path for the arc and setting the line width to something large. This is what I have so far:
CAShapeLayer *layer = (CAShapeLayer *)self.layer;
UIBezierPath *bezierPath = [UIBezierPath bezierPath];
CGPoint startPoint = CGPointMake(self.bounds.origin.x, self.bounds.origin.y + self.bounds.size.height / 2);
[bezierPath moveToPoint:startPoint];
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor redColor].CGColor;
CGFloat strokeSize = 10;
CGPoint endPoint = CGPointMake(self.bounds.origin.x + self.bounds.size.width, self.bounds.origin.y + self.bounds.size.height / 2);
[bezierPath setLineWidth:100];
[bezierPath addQuadCurveToPoint:endPoint controlPoint:CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2, self.bounds.origin.y)];
bezierPath.lineCapStyle = kCGLineCapRound;
layer.path = bezierPath.CGPath;
When I see my arc though, it doesn't look any bigger than a thin path. Is this the way to create something like that? Or do I need to create two paths and somehow fill the area between them?
You need to set the layer's lineWidth, not the bezier path's,
layer.lineWidth = 100;

Resources