How to Swipe UIView on Button Action in all four directions

855 Views Asked by At

I have Two UIButtons on Right and Left and a UIView At Middle of the button..

I have to swipe ContainerView with some animation on UIButton click..

If user tap on right button ContainerView swipe to .right direction....If user tap on Left button ContainerView swipe to .left direction..

I have not found it anyWhere....Need help with full coding part

I have done this on my view

override func viewDidAppear(_ animated: Bool) {
    leftSwipe()
    rightSwipe()
}

 //MARK:Left Swipe Function
func leftSwipe()
{
    let swipeLeft = UISwipeGestureRecognizer()
    swipeLeft.direction = .left   
    self.insideContainerViewSecond.addGestureRecognizer(swipeLeft)
    swipeLeft.addTarget(self, action: #selector(swipe(sender:)))
}

//MARK:Right Swipe Function
func rightSwipe()
{
    let swipeRight = UISwipeGestureRecognizer()
    swipeRight.direction = .right  
    self.insideContainerViewSecond.addGestureRecognizer(swipeRight)
    swipeRight.addTarget(self, action: #selector(swipe(sender:)))
}

//MARK: Swipe Function
@objc func swipe(sender: UISwipeGestureRecognizer)
{
    switch sender.direction
    {
    case .left:
        print("swiped left")
    case .right:
        print("swiped right")
    default:
        print("no action")
    }
}

In this image I have a UIView and two button right and left..When I swipe on my UIView It swipe Left and right without animation.....But I need to swipe my UIView on right or Left button action with flip animation

enter image description here

2

There are 2 best solutions below

2
Baran Karaoğuz On

We have CATransition Classes with iOS. You should use this. Or you should constraint animation. Maybe this repo is helped you for first trick.

https://github.com/barankaraoguzzz/FastOnBoarding/blob/master/FOView/Classes/FOAnimation.swift

if this answer doesn't be true for this question. Come again :)

0
DonMag On

You have a couple different questions...

How to "simulate" a swipe-gesture on a button tap?

You could do this different ways, such as creating a showNextImage() function, and then call it on swipe-left or on right-button-tap.

Or, you could do something like this, where you create a temporary swipe gesture recognizer and pass it to your recognizer function:

@objc func leftButtonTap(_ sender: UIButton)
{
    // create a right-swipe-gesture
    let sgr = UISwipeGestureRecognizer()
    sgr.direction = .right
    self.swipe(sender: sgr)
}

@objc func rightButtonTap(_ sender: UIButton)
{
    // create a left-swipe-gesture
    let sgr = UISwipeGestureRecognizer()
    sgr.direction = .left
    self.swipe(sender: sgr)
}

You said on swipe (or button tap), you want to use flip animation to show the next (or previous) image?

You can do this by adding two image views to your "container" view. Set one view hidden. When you want to "show the next image," set the .image property of the hidden imageView and then use UIView.transition(...) to flip from the visible imageView to the hidden imageView:

private func flipMe(_ direction: UIView.AnimationOptions) -> Void {
    // fromView is the one that is NOT hidden
    let fromView = imgViewB.isHidden ? imgViewA : imgViewB
    
    // toView is the one that IS hidden
    let toView = imgViewB.isHidden ? imgViewB : imgViewA
    
    UIView.transition(from: fromView,
                      to: toView,
                      duration: 0.5,
                      options: [direction, .showHideTransitionViews],
                      completion: { b in
                        // if we want to do something on completion
                      })
}

Here is a simple example that you can run and see what happens. No @IBOutlet or @IBAction connections, so you don't need any Storyboard setup:

FlipView custom view subclass:

class FlipView: UIView {
    
    // set image names from controller
    var imageNames: [String] = [] {
        didSet {
            if let img = UIImage(named: imageNames[0]) {
                imgViewB.image = img
            } else {
                imgViewB.image = testImage()
            }
        }
    }
    
    // index counter
    private var idx: Int = 0
    
    // two image views
    private let imgViewA: UIImageView = UIImageView()
    private let imgViewB: UIImageView = UIImageView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        
        // add both image views
        // with light-gray backgrounds
        // constraining all 4 sides to self
        [imgViewA, imgViewB].forEach { v in
            v.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
            addSubview(v)
            v.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                v.topAnchor.constraint(equalTo: topAnchor),
                v.leadingAnchor.constraint(equalTo: leadingAnchor),
                v.trailingAnchor.constraint(equalTo: trailingAnchor),
                v.bottomAnchor.constraint(equalTo: bottomAnchor),
            ])
        }
        
        // start with one of the image views hidden
        imgViewA.isHidden = true
        
    }
    
    private func flipMe(_ direction: UIView.AnimationOptions) -> Void {
        // fromView is the one that is NOT hidden
        let fromView = imgViewB.isHidden ? imgViewA : imgViewB
        
        // toView is the one that IS hidden
        let toView = imgViewB.isHidden ? imgViewB : imgViewA
        
        UIView.transition(from: fromView,
                          to: toView,
                          duration: 0.5,
                          options: [direction, .showHideTransitionViews],
                          completion: { b in
                            // if we want to do something on completion
                          })
    }
    
    func flipToPrevious() -> Void {
        // don't try to flip past the first image
        if idx == 0 {
            return
        }
        
        // decrement the index
        idx -= 1
        
        let hiddenImageView = imgViewA.isHidden ? imgViewA : imgViewB
        // get the previous image
        if let img = UIImage(named: imageNames[idx]) {
            hiddenImageView.image = img
        } else {
            hiddenImageView.image = testImage()
        }
        
        // flip it from left
        flipMe(.transitionFlipFromLeft)
    }

    func flipToNext() -> Void {
        // don't try to flip past the last image
        if idx == imageNames.count - 1 {
            return
        }
        
        // increment the index
        idx += 1
        
        let hiddenImageView = imgViewA.isHidden ? imgViewA : imgViewB
        // get the next image
        if let img = UIImage(named: imageNames[idx]) {
            hiddenImageView.image = img
        } else {
            hiddenImageView.image = testImage()
        }
        
        // flip it from right
        flipMe(.transitionFlipFromRight)
    }
    
    // get a numbered system image if the named image
    //  cannot be loaded from assets
    private func testImage() -> UIImage {
        let colors: [UIColor] = [
            .systemRed, .systemGreen, .systemBlue,
            .systemYellow, .systemTeal, .systemPurple,
        ]
        guard let img = UIImage(systemName: "\(idx+1).circle") else {
            // that should not fail, but in case it does
            return UIImage()
        }
        return img.withTintColor(colors[idx % colors.count], renderingMode: .alwaysOriginal)
    }
}

ViewController example ViewController class:

class ViewController: UIViewController {
    
    let insideContainerViewSecond: FlipView = FlipView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // respect safe area
        let g = view.safeAreaLayoutGuide
    
        // create left and right buttons
        let leftButton = UIButton()
        leftButton.translatesAutoresizingMaskIntoConstraints = false
        let leftImg = UIImage(systemName: "chevron.left.circle.fill")
        leftButton.setImage(leftImg, for: [])
        leftButton.addTarget(self, action: #selector(leftButtonTap(_:)), for: .touchUpInside)
        
        let rightButton = UIButton()
        rightButton.translatesAutoresizingMaskIntoConstraints = false
        let rightImg = UIImage(systemName: "chevron.right.circle.fill")
        rightButton.setImage(rightImg, for: [])
        rightButton.addTarget(self, action: #selector(rightButtonTap(_:)), for: .touchUpInside)
        
        insideContainerViewSecond.translatesAutoresizingMaskIntoConstraints = false
        
        view.addSubview(insideContainerViewSecond)
        view.addSubview(leftButton)
        view.addSubview(rightButton)
        
        NSLayoutConstraint.activate([
            
            insideContainerViewSecond.topAnchor.constraint(equalTo: g.topAnchor, constant: 80.0),
            insideContainerViewSecond.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 80.0),
            insideContainerViewSecond.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -80.0),
            insideContainerViewSecond.heightAnchor.constraint(equalTo: insideContainerViewSecond.widthAnchor, multiplier: 0.5),
            
            leftButton.centerYAnchor.constraint(equalTo: insideContainerViewSecond.topAnchor),
            leftButton.centerXAnchor.constraint(equalTo: insideContainerViewSecond.leadingAnchor),
            
            rightButton.centerYAnchor.constraint(equalTo: insideContainerViewSecond.topAnchor),
            rightButton.centerXAnchor.constraint(equalTo: insideContainerViewSecond.trailingAnchor),
            
        ])

        // your array of image names
        let imageNames: [String] = [
            "pic1", "pic2", "pic3", "pic4", "pic5", "pic6",
        ]

        insideContainerViewSecond.imageNames = imageNames

        leftSwipe()
        rightSwipe()
    }

    //MARK:Left Swipe Function
    func leftSwipe()
    {
        let swipeLeft = UISwipeGestureRecognizer()
        swipeLeft.direction = .left
        self.insideContainerViewSecond.addGestureRecognizer(swipeLeft)
        swipeLeft.addTarget(self, action: #selector(swipe(sender:)))
    }
    
    //MARK:Right Swipe Function
    func rightSwipe()
    {
        let swipeRight = UISwipeGestureRecognizer()
        swipeRight.direction = .right
        self.insideContainerViewSecond.addGestureRecognizer(swipeRight)
        swipeRight.addTarget(self, action: #selector(swipe(sender:)))
    }
    
    //MARK: Swipe Function
    @objc func swipe(sender: UISwipeGestureRecognizer)
    {
        switch sender.direction
        {
        case .left:
            print("swiped left")
            self.insideContainerViewSecond.flipToNext()
        case .right:
            print("swiped right")
            self.insideContainerViewSecond.flipToPrevious()
        default:
            print("no action")
        }
    }

    @objc func leftButtonTap(_ sender: UIButton)
    {
        // create a right-swipe-gesture
        let sgr = UISwipeGestureRecognizer()
        sgr.direction = .right
        self.swipe(sender: sgr)
    }

    @objc func rightButtonTap(_ sender: UIButton)
    {
        // create a left-swipe-gesture
        let sgr = UISwipeGestureRecognizer()
        sgr.direction = .left
        self.swipe(sender: sgr)
    }

}