1

I'm trying to draw a bezier path with a quadratic curve in the middle. The curve works well on iPhone 8 and XS, but is not responsive (i.e. not rendered correctly) on other devices.

Below is the image of the curve in iPhone XS (correct)

enter image description here

and iPhone XR (incorrect)

enter image description here

I've tried to use the view's constraint to get the middle value of the line but somehow it still not working

Here is the code where i'm drawing the path:

//self.viewTabBorder is the grey line, which is a uiview with 1 pixel height
override func viewWillAppear(_ animated: Bool) {
        let path = UIBezierPath()
        path.move(to: CGPoint(x: self.viewTabBorder.center.x - self.btnHome.frame.width + 20, y: 0))
        path.addQuadCurve(to: CGPoint(x: self.viewTabBorder.center.x + self.btnHome.frame.size.width - 20, y: 0), controlPoint: CGPoint(x: self.viewTabBorder.center.x, y: self.btnHome.frame.height + 5))
        path.addLine(to: CGPoint(x: self.viewTabBorder.center.x + self.btnHome.frame.size.width - 20, y: 0))

        let line = CAShapeLayer()
        line.path = path.cgPath
        line.strokeColor = UIColor(red: 224, green: 224, blue: 224).cgColor
        line.fillColor = UIColor.white.cgColor
        self.view.layer.addSublayer(line)
        self.viewTabBorder.layer.addSublayer(line)
    }

Can anyone show me what i'm missing? Thank you very much in advance!

Rob
  • 415,655
  • 72
  • 787
  • 1,044
hrtlkr29
  • 383
  • 1
  • 7
  • 21
  • Upload a screen shot of the profiler, otherwise people have nothing to work off of – Alexander Jul 09 '19 at 03:15
  • @Alexander sorry i'm still new to swift. Can you show me what exactly a profiler is? – hrtlkr29 Jul 09 '19 at 03:17
  • https://www.raywenderlich.com/397-instruments-tutorial-with-swift-getting-started – Alexander Jul 09 '19 at 03:21
  • @Alexander thank you for the link. Below is the link of the screenshot of the profiler that i just took: https://imgur.com/a/Bx9c8WA – hrtlkr29 Jul 09 '19 at 03:36
  • Investigate what caused that CPU spike – Alexander Jul 09 '19 at 03:38
  • So there are two methods which is causing the CPU spike: 1/ AppDelegate: i'm checking some user permission here with promisekit. 2/ A method that is "not in a known library range and cannot be symbolicated", so it returns "not available" when i try to investigate more https://imgur.com/a/gG7kS3f – hrtlkr29 Jul 09 '19 at 03:52
  • I can't help much here, but I think that should be enough info to give some leads to potential answerers. Edit your post and detail everything you just commented, including in-line screen shots – Alexander Jul 09 '19 at 04:13
  • When you say “not responsive”, are you saying that it’s slow? Or are you saying “responsive” in the web designer sense, that it’s not adapting to the different screen sizes appropriately? I’m assuming you meant the latter (which is an issue here, which I’ve answered below, regardless to any performance concerns you might have), not the former. – Rob Jul 09 '19 at 05:56
  • 1
    Unrelated, but when you override any of these view lifecycle methods, it’s prudent to always call the `super` implementation, too. – Rob Jul 09 '19 at 07:04
  • @Rob sorry if my English confused you. My "responsive" here means the responsive in web design sense. – hrtlkr29 Jul 09 '19 at 10:41
  • No worries. I suspected that’s what you meant. Hopefully my answer below addresses your issue. It’s simply that this discussion w Alexander regarding Instruments graphs was obviously predicated on the assumption that you were concerned about the speed/performance of the app and has nothing to do with your question here. ;) – Rob Jul 09 '19 at 14:59
  • Thank you for editing my question and the answer below. I'll be working on it! – hrtlkr29 Jul 10 '19 at 09:29

1 Answers1

1

A couple of observations:

  1. You are defining paths for sublayers to views. Doing this in viewWillAppear is too early in the process. The layout engine may not be done applying constraints, placing the views in their final location. Do the defining of the paths in viewDidLayoutSubviews, not in viewWillAppear (nor viewDidLoad, nor viewWillLayoutSubviews).

    This also has the virtue that should you ever change your app to support multiple orientations or do any changes that affect the constraints in the view, this viewDidLayoutSubviews we be called again so these sublayers will be properly updated as needed. If you use viewWillAppear your app will not support dynamic changes to your views (should you ever need that).

  2. That having been said, be aware that viewDidLayoutSubviews can be called multiple times. So you can, for example, add the sublayers in viewDidLoad, but update their paths in viewDidLayoutSubviews.

  3. It is likely not an issue here, but I would suggest you avoid using frame or center when defining a path for a sublayer. Remember that these two properties are defined in the coordinate system of their superview. I’d suggest you always use a view’s bounds (defined in a view’s own coordinate system), not its frame (defined in its superview’s coordinate system) when trying to define a path for a sublayer. And if you want, for example, the horizontal center of a view when defining a sublayer’s path, use bounds.midX not center.x.

    Sometimes this won’t matter (if the view goes edge-to-edge within its superview), but (a) it suggests a misunderstanding of the different coordinate systems; and (b) if you ever add safe areas or otherwise adjust the placement of the view, using the frame/center will get you into trouble.


A slightly more advanced concept: Once you have your immediate issue behind you, you might consider moving this configuration of subviews into a UIView subclass (using its layoutSubviews method), possibly even making it an @IBDesignable class so you can see this rendered in Interface Builder. Or, another approach is to wrap this in a container view controller. But either way, this can help prevent view controller “bloat”. It’s probably a bit beyond the scope of this question, but something to consider as you move forward.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you for a very thorough explanation. Solved the problem by doing the steps as you instructed! I will also try other concepts that you suggest. Totally saved my day – hrtlkr29 Jul 10 '19 at 09:43