Asked  7 Months ago    Answers:  5   Viewed   34 times

Is there a way to set cornerRadius for only top-left and top-right corner of a UIView?

I tried the following, but it end up not seeing the view anymore.

UIView *view = [[UIView alloc] initWithFrame:frame];

CALayer *layer = [CALayer layer];
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:frame byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight) cornerRadii:CGSizeMake(3.0, 3.0)];
layer.shadowPath = shadowPath.CGPath;
view.layer.mask = layer;

 Answers

44

Pay attention to the fact that if you have layout constraints attached to it, you must refresh this as follows in your UIView subclass:

override func layoutSubviews() {
    super.layoutSubviews()
    roundCorners(corners: [.topLeft, .topRight], radius: 3.0)
}

If you don't do that it won't show up.


And to round corners, use the extension:

extension UIView {
   func roundCorners(corners: UIRectCorner, radius: CGFloat) {
        let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
        let mask = CAShapeLayer()
        mask.path = path.cgPath
        layer.mask = mask
    }
}


Additional view controller case: Whether you can't or wouldn't want to subclass a view, you can still round a view. Do it from its view controller by overriding the viewWillLayoutSubviews() function, as follows:

class MyVC: UIViewController {
    /// The view to round the top-left and top-right hand corners
    let theView: UIView = {
        let v = UIView(frame: CGRect(x: 10, y: 10, width: 200, height: 200))
        v.backgroundColor = .red
        return v
    }()
    
    override func loadView() {
        super.loadView()
        view.addSubview(theView)
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()

        // Call the roundCorners() func right there.
        theView.roundCorners(corners: [.topLeft, .topRight], radius: 30)
    }
}
Tuesday, June 1, 2021
 
sassy_geekette
answered 7 Months ago
81

You just need to mask the layer as shown below:

For Swift 3:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: [.bottomLeft , .bottomRight , .topLeft], cornerRadii: CGSize(width: 20, height: 20)).cgPath

self.myView.layer.backgroundColor = UIColor.green.cgColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape

Lower Version:

let rectShape = CAShapeLayer()
rectShape.bounds = self.myView.frame
rectShape.position = self.myView.center
rectShape.path = UIBezierPath(roundedRect: self.myView.bounds, byRoundingCorners: .BottomLeft | .BottomRight | .TopLeft, cornerRadii: CGSize(width: 20, height: 20)).CGPath

self.myView.layer.backgroundColor = UIColor.greenColor().CGColor
//Here I'm masking the textView's layer with rectShape layer
self.myView.layer.mask = rectShape
Thursday, June 3, 2021
 
elias
answered 6 Months ago
20

It seems that UIApplication is dispatching a message to the active view controller.

But how does your View Controller instance get these messages?

The message is forwarded to the first view controller whose view has been added to the UIWindow instance.

This boils down to 3 basic scenarios:

  1. The ViewController whose view is added directly to the UIWindow instance (single view app)

  2. The navigation Controller in a Navigation based app, then the navigation controller forwards the message to the active views view controller.

  3. The tab bar Controller in a tab bar based app, then the tab bar controller forwards the message to the active views view controller (or the active navigation controller).

The problem you will have, is if you build an app with multiple views, but DO NOT use a Navigation controller or Tab Bar controller. If you swap views in and out of the UIWindow instance manually, you will not receive these messages reliably. This is similar to posts like this one: iPhone viewWillAppear not firing

Just use Apple's conventions for multiple views and you be fine. Hope this saves some one an hour or two

Sunday, August 1, 2021
 
providence
answered 4 Months ago
52

Try it as mentioned by shwet-solanki, but add the following line after changing the constraint:

[self.view layoutIfNeeded];

the IBAction would look like:

- (IBAction)expandYellowBox:(id)sender {

[UIView animateWithDuration:0.5
                 animations:^{
                     self.yellowBoxHeightConstraint.constant += 50;
                     [self.view layoutIfNeeded];
                 }];
}

Where yellowBoxHeightConstraint is the IBOutlet for height constraint of yellowBox. Hope this helps.

Sunday, August 8, 2021
 
pamelus
answered 4 Months ago
41

<div style="position: relative; width: 250px;">
  <div style="position: absolute; top: 0; right: 0; width: 100px; text-align:right;">
    here
  </div>
  <div style="position: absolute; bottom: 0; right: 0; width: 100px; text-align:right;">
    and here
  </div>
  Lorem Ipsum etc <br />
  blah <br />
  blah blah <br />
  blah <br />
  lorem ipsums
</div>

Gets you pretty close, although you may need to tweak the "top" and "bottom" values.

Thursday, October 7, 2021
 
Tomasz Mularczyk
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share