forked from shadowfacts/Tusker
Improve compose reply view avatar scrolling animation
This commit is contained in:
parent
1358152dec
commit
bcf2a2f026
|
@ -39,6 +39,7 @@ extension TextViewCaretScrolling {
|
||||||
|
|
||||||
let animator = UIViewPropertyAnimator(duration: 0.2, curve: .easeInOut) {
|
let animator = UIViewPropertyAnimator(duration: 0.2, curve: .easeInOut) {
|
||||||
scrollView.scrollRectToVisible(rectToMakeVisible, animated: false)
|
scrollView.scrollRectToVisible(rectToMakeVisible, animated: false)
|
||||||
|
scrollView.layoutIfNeeded()
|
||||||
}
|
}
|
||||||
self.caretScrollPositionAnimator = animator
|
self.caretScrollPositionAnimator = animator
|
||||||
animator.startAnimation()
|
animator.startAnimation()
|
||||||
|
|
|
@ -76,13 +76,15 @@ struct ReplyStatusView: View {
|
||||||
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
|
// once you scroll past the in-reply-to-content, the bottom of the avatar should be pinned to the bottom of the content
|
||||||
offset = min(offset, maxOffset)
|
offset = min(offset, maxOffset)
|
||||||
|
|
||||||
return AvatarImageView(
|
return AvatarContainerRepresentable(offset: offset) {
|
||||||
url: status.account.avatar,
|
AvatarImageView(
|
||||||
size: 50,
|
url: status.account.avatar,
|
||||||
style: controller.config.avatarStyle,
|
size: 50,
|
||||||
fetchAvatar: controller.fetchAvatar
|
style: controller.config.avatarStyle,
|
||||||
)
|
fetchAvatar: controller.fetchAvatar
|
||||||
.offset(x: 0, y: offset)
|
)
|
||||||
|
}
|
||||||
|
.frame(width: 50, height: 50)
|
||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,3 +96,39 @@ private struct DisplayNameHeightPrefKey: PreferenceKey {
|
||||||
value = nextValue()
|
value = nextValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This whole dance is necessary so that the offset can be animatable from
|
||||||
|
// UIKit animations, like TextViewCaretScrolling.
|
||||||
|
private struct AvatarContainerRepresentable<Content: View>: UIViewControllerRepresentable {
|
||||||
|
let offset: CGFloat
|
||||||
|
@ViewBuilder let content: Content
|
||||||
|
|
||||||
|
func makeUIViewController(context: Context) -> Controller {
|
||||||
|
Controller(host: UIHostingController(rootView: content))
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIViewController(_ uiViewController: Controller, context: Context) {
|
||||||
|
uiViewController.host.rootView = content
|
||||||
|
uiViewController.host.view.transform = CGAffineTransform(translationX: 0, y: offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This extra layer is necessary because applying a transform to the
|
||||||
|
// representable's VC's view doesn't seem to have an effect.
|
||||||
|
class Controller: UIViewController {
|
||||||
|
let host: UIHostingController<Content>
|
||||||
|
|
||||||
|
init(host: UIHostingController<Content>) {
|
||||||
|
self.host = host
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
addChild(host)
|
||||||
|
host.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
|
view.addSubview(host.view)
|
||||||
|
host.view.frame = view.bounds
|
||||||
|
host.didMove(toParent: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue