ephread/Instructions

Wrong position coach marks inside a scrollview

Lailan opened this issue · 4 comments

Describe the bug

Good afternoon.
I am trying to use the library in my project, but I am facing the following problem:

I have a view that is inside a UIScrollView, when I need to show the coach mark in a place that is not visible, I scroll down the screen but the location of the coach mark is wrong. (See the GIF)

How can I fix this problem?

Environment:

  • Device: iPhone X
  • iOS version: 13
  • Instructions version: master
  • Dependency Manager: CocoaPods

Example GIF
RPReplay_Final1589398754

Hey there @Lailan, my guess is that the current offset of the scroll view is not taken into account. The helper making the conversion doesn't work with scroll views, since —I believe— UIView.convert itself ignores the content offset.

The default window and the window used by Instructions share the same coordinates, so you could try to convert the coordinates of your view into its window coordinate system withUIView.convert and then manually substract the scrollview offset from its origin.

I should probably add something in the README.

By the way, thanks for taking the time to provide a video, it's really appreciated!

Thanks for the quick response.
Do you have any examples of how I can do this?

Maybe something like this, but it's just from the top of my head. I can have a deeper look, but probably not before a few days. I should probably deal with this case in the helper.

var coachMark = coachMarksController.helper.makeCoachMark(for: pointOfInterest)

let rect = view.window!.convert(viewOfInterest.frame, from: viewOfInterest.superview)
rect = CGRect(x: rect + scrollView.contentOffset.x,
              x: rect + scrollView.contentOffset.y,
              width: rect.width,
              height: rect.height)

coachMark.cutoutPath = UIBezierPath(roundedRect: rect.insetBy(dx: -4, dy: -4),
                                    byRoundingCorners: .allCorners,
                                    cornerRadii: CGSize(width: 4, height: 4))

It Works!
Thanks for the support.

let coachMark = coachMarksController.helper.makeCoachMark(for: self.viewAlunos) {
            (frame: CGRect) -> UIBezierPath in
                var rect = self.view.window!.convert(self.viewAlunos.frame, from: self.viewAlunos.superview)
                rect = CGRect(x: rect.origin.x,
                              y: rect.origin.y - bottomOffset.y,
                              width: rect.width,
                              height: rect.height)
                return  UIBezierPath(roundedRect: rect.insetBy(dx: -4, dy: -4),
                                                   byRoundingCorners: .allCorners,
                                                   cornerRadii: CGSize(width: 4, height: 4))
            }

RPReplay_Final1589411200