Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // FeedbackBottomSheetVC.swift
- // BeFriends
- //
- // Created by Ramesh Sanghar on 18/04/23.
- //
- import UIKit
- class FeedbackBottomSheetVC: UIViewController {
- // 1
- lazy var containerView: UIView = {
- let view = UIView()
- view.backgroundColor = .white
- view.layer.cornerRadius = 16
- view.clipsToBounds = true
- return view
- }()
- // define lazy views
- lazy var titleLabel: UILabel = {
- let label = UILabel()
- label.textColor = .lightGray
- label.translatesAutoresizingMaskIntoConstraints = false
- label.text = "FEEDBACK"
- label.font = .systemFont(ofSize: 15, weight: .light)
- return label
- }()
- lazy var sendBtn: UIButton = {
- let button = UIButton(type: .system)
- button.setTitle("SEND", for: .normal)
- button.setTitleColor(StaticValues.TINT_COLOR, for: .normal)
- button.translatesAutoresizingMaskIntoConstraints = false
- button.addTarget(self, action: #selector(sendAction), for: .touchUpInside)
- return button
- }()
- lazy var lineView: UIView = {
- let line = UIView()
- line.translatesAutoresizingMaskIntoConstraints = false
- line.backgroundColor = StaticValues.TINT_COLOR
- return line
- }()
- // define lazy views
- lazy var feedBackTextView: UITextView = {
- let text = UITextView()
- text.textColor = .lightGray
- text.translatesAutoresizingMaskIntoConstraints = false
- text.text = "Your Text Here..."
- text.font = .systemFont(ofSize: 18, weight: .regular)
- return text
- }()
- // 2
- let maxDimmedAlpha: CGFloat = 0.6
- lazy var dimmedView: UIView = {
- let view = UIView()
- view.backgroundColor = .black
- view.alpha = maxDimmedAlpha
- return view
- }()
- let defaultHeight: CGFloat = 300
- let dismissibleHeight: CGFloat = 200
- let maximumContainerHeight: CGFloat = UIScreen.main.bounds.height - 64
- // keep updated with new height
- var currentContainerHeight: CGFloat = 300
- // 3. Dynamic container constraint
- var containerViewHeightConstraint: NSLayoutConstraint?
- var containerViewBottomConstraint: NSLayoutConstraint?
- var isLargeSizeEnabled = true
- override func viewDidLoad() {
- super.viewDidLoad()
- setupView()
- setupConstraints()
- setupPanGesture()
- }
- override func viewDidAppear(_ animated: Bool) {
- super.viewDidAppear(animated)
- animateShowDimmedView()
- animatePresentContainer()
- }
- override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
- let touch = touches.first
- if touch?.view == dimmedView {
- animateDismissView()
- }
- }
- @objc private func sendAction() {
- }
- func setupView() {
- view.backgroundColor = .clear
- }
- @objc func handlePanGesture(gesture: UIPanGestureRecognizer) {
- let translation = gesture.translation(in: view)
- // Drag to top will be minus value and vice versa
- // print("Pan gesture y offset: \(translation.y)")
- // Get drag direction
- let isDraggingDown = translation.y > 0
- // print("Dragging direction: \(isDraggingDown ? "going down" : "going up")")
- // New height is based on value of dragging plus current container height
- let newHeight = currentContainerHeight - translation.y
- // Handle based on gesture state
- switch gesture.state {
- case .changed:
- // This state will occur when user is dragging
- if newHeight < maximumContainerHeight {
- // Keep updating the height constraint
- containerViewHeightConstraint?.constant = newHeight
- // refresh layout
- view.layoutIfNeeded()
- }
- case .ended:
- // This happens when user stop drag,
- // so we will get the last height of container
- // Condition 1: If new height is below min, dismiss controller
- if newHeight < dismissibleHeight {
- self.animateDismissView()
- }
- else if newHeight < defaultHeight {
- // Condition 2: If new height is below default, animate back to default
- animateContainerHeight(defaultHeight)
- }
- else if newHeight < maximumContainerHeight && isDraggingDown {
- // Condition 3: If new height is below max and going down, set to default height
- animateContainerHeight(defaultHeight)
- }
- else if newHeight > defaultHeight && !isDraggingDown {
- // Condition 4: If new height is below max and going up, set to max height at top
- animateContainerHeight(maximumContainerHeight)
- }
- default:
- break
- }
- }
- func animateContainerHeight(_ height: CGFloat) {
- UIView.animate(withDuration: 0.4) {
- // Update container height
- self.containerViewHeightConstraint?.constant = height
- // Call this to trigger refresh constraint
- self.view.layoutIfNeeded()
- }
- // Save current height
- currentContainerHeight = height
- }
- func setupPanGesture() {
- // add pan gesture recognizer to the view controller's view (the whole screen)
- let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture(gesture:)))
- // change to false to immediately listen on gesture movement
- panGesture.delaysTouchesBegan = false
- panGesture.delaysTouchesEnded = false
- view.addGestureRecognizer(panGesture)
- }
- func animateShowDimmedView() {
- dimmedView.alpha = 0
- UIView.animate(withDuration: 0.4) {
- self.dimmedView.alpha = self.maxDimmedAlpha
- }
- }
- func animatePresentContainer() {
- // Update bottom constraint in animation block
- UIView.animate(withDuration: 0.3) {
- self.containerViewBottomConstraint?.constant = 0
- // Call this to trigger refresh constraint
- self.view.layoutIfNeeded()
- }
- }
- func animateDismissView() {
- // hide main container view by updating bottom constraint in animation block
- UIView.animate(withDuration: 0.3) {
- self.containerViewBottomConstraint?.constant = self.defaultHeight
- // call this to trigger refresh constraint
- self.view.layoutIfNeeded()
- }
- // hide blur view
- dimmedView.alpha = maxDimmedAlpha
- UIView.animate(withDuration: 0.4) {
- self.dimmedView.alpha = 0
- } completion: { _ in
- // once done, dismiss without animation
- self.dismiss(animated: false)
- }
- }
- func setupConstraints() {
- // 4. Add subviews
- view.addSubview(dimmedView)
- view.addSubview(containerView)
- dimmedView.translatesAutoresizingMaskIntoConstraints = false
- containerView.translatesAutoresizingMaskIntoConstraints = false
- containerView.addSubview(titleLabel)
- containerView.addSubview(sendBtn)
- containerView.addSubview(lineView)
- containerView.addSubview(feedBackTextView)
- // 5. Set static constraints
- NSLayoutConstraint.activate([
- // set dimmedView edges to superview
- dimmedView.topAnchor.constraint(equalTo: view.topAnchor),
- dimmedView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
- dimmedView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- dimmedView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- // set container static constraint (trailing & leading)
- containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
- containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
- //containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: defaultHeight)
- ])
- // 6. Set container to default height
- containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: defaultHeight)
- // 7. Set bottom constant to 0
- containerViewBottomConstraint = containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
- // Activate constraints
- containerViewHeightConstraint?.isActive = true
- containerViewBottomConstraint?.isActive = true
- NSLayoutConstraint.activate([
- // TitleLbl
- titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 12),
- titleLabel.heightAnchor.constraint(equalToConstant: 20),
- titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10),
- titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -10),
- ])
- NSLayoutConstraint.activate([
- // Send Btn
- sendBtn.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor),
- sendBtn.widthAnchor.constraint(equalToConstant: 80),
- sendBtn.heightAnchor.constraint(equalToConstant: 30),
- sendBtn.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5),
- ])
- NSLayoutConstraint.activate([
- // Line View
- lineView.topAnchor.constraint(equalTo: sendBtn.bottomAnchor, constant: 5),
- lineView.heightAnchor.constraint(equalToConstant: 1),
- lineView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -10),
- lineView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10)
- ])
- NSLayoutConstraint.activate([
- // Feedback Text View
- feedBackTextView.topAnchor.constraint(equalTo: lineView.bottomAnchor, constant: 18),
- feedBackTextView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -30),
- feedBackTextView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -10),
- feedBackTextView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 10)
- ])
- }
- }
- let vc = ShareBottomSheetVC()
- vc.modalPresentationStyle = .overCurrentContext
- // Keep animated value as false
- // Custom Modal presentation animation will be handled in VC itself
- self.present(vc, animated: false)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement