【Swift4】Tinder風UI(ユーザーインターフェース)の作成方法


はじめに

どうも、とがみんです。現在、セブ島にあるプログラミングと英語の両方を学ぶことができるNexSeedという学校でエンジニアインターンをしています。

留学していた時の記事はこちらです。

>NexSeedでのセブ島エンジニア留学を振り返ってみる。

主に、Swiftを使ったiOSアプリ開発コースのティーチングアシスタントをしていて、

今は生徒たちが、それぞれiOSアプリのアイデアを考えて、その開発を頑張っているところです。

自分は生徒たちが実装したい機能、実装にあたって詰まりそうな機能を先回りして実装し、ヒントを出したり、その機能の実装方法を授業として解説したりしています。

そんな中で、マッチングアプリでお馴染みの「Tinder風のUI」が結構人気で、その実装方法を考えたので、この記事で紹介したいと思います。

Tinder風のUIのデモ

以下が今回作成した、Tinder風のUIのデモです。スワイプした方向にカードが飛んでいき、スワイプする方向によって処理を変えることができます。リセットボタンを押すと、元に戻ります。

Tinder風UI実装の仕方

1.UIの配置について

画面には、2つのUIViewにそれぞれUIImageViewが追加されています。複数枚カードがあるように見えますが、「frontCard」と「backCard」の2枚だけです。

手前にある「frontCard」にのみ、「Pan Gesture Recognitionnizer」がついています。

手前の「frontCard」のみが動き、「backCard」は静止したままで、スワイプされた時「frontCard」がどこかへ行ってしまうように見えますが、実際は行った後すぐに元の位置に戻っています。中の画像の情報のみが移動していく仕組みになっています。その処理について、詳しく考えていきます。

2.スワイプした時の処理について

スワイプした時に、スワイプした距離に応じて、x座標を動かし、画面の大きさに対して、スワイプした割合に応じて、カードを傾ける処理を書きます。

//手前のカードをスワイプした分だけ、横に動かし、動かした距離に応じて回転させる。
//「point.x」に0.1をかけているのは、スワイプした時に動きすぎないようにするため。

//スワイプした時にx座標だけ動かす。
swipeCard.center = CGPoint(x: swipeCard.center.x + point.x * 0.1,y:swipeCard.center.y)
//Max45度の傾き。スワイプした距離に応じて傾きを変える
swipeCard.transform = CGAffineTransform(rotationAngle: swipeDistanceX/(view.frame.width/2) * -0.785)

スワイプした時の処理に関しては、スワイプして指が離れた時点で、小さくスワイプしていた場合と、大きくスワイプした場合で分けます。

//スワイプの指が離れたときの処理.
if sender.state == UIGestureRecognizerState.ended{
    //処理を記入
    //左に大きく振れた時
    if swipeCard.center.x < self.screenWidth/5 {
        UIView.animate(withDuration: 0, animations: {

        })
    }
    //右に大きく振れた時
    else if swipeCard.center.x > self.screenWidth - self.screenWidth/5{
        UIView.animate(withDuration: 0, animations: {

        })
    }
    //小さく振れた時
    else {
        UIView.animate(withDuration: 0.2, animations: {

        })
    }
}

カードを小さくスワイプした時は、元の位置に戻します。

//小さく振れた時、カードを元の位置に戻す
swipeCard.center = CGPoint(x: self.cardCenter.x,y:self.cardCenter.y)
swipeCard.transform = .identity

カードを大きくスワイプした時は、以下の手順で処理を実装します。以下には左側にスワイプした時の処理しか書いていませんが、右側にスワイプした場合の処理も同様に実装することができます。

  • スワイプした方向にカードを飛ばす。
  swipeCard.center = CGPoint(x: self.cardCenter.x + self.screenWidth,y:self.cardCenter.y)
  • 飛ばしたカードの情報を保持する(処理する)。

  • self.leftInfo.append(self.imageList[self.cardNum])
    print("左スワイプデータ:",self.leftInfo)
    
  • 飛ばしたカードを透明にする。

  • swipeCard.alpha = 0
    
  • 透明にした後、カードを元の位置に戻す。この時、「frontCard」と「backCard」の両方が画面に存在するが、「frontCard」は透明なので、「backCard」のみが見えている状態になります。

  • swipeCard.center = CGPoint(x: self.cardCenter.x,y:self.cardCenter.y)
    swipeCard.transform = .identity
    
  • 「frontCard」カードに、「backCard」の情報を入れます。同じデザインのカードが2枚ある状態で、手前は透明です。
  self.frontCardImage.image = self.backCardImage.image
  • 「frontCard」カードを見えるようにする。
  swipeCard.alpha = 1
  • 最後に「backCard」に次の要素の情報を入れます。この時、最後から2枚目の場合と最後のカードの場合は場合分が必要になります。「backCard」に入れる情報がなくなり、「Out of range」のエラーがでてしまうので。
  //(1)カードが残り2枚になるまで
  if self.cardNum < self.imageCount - 2{
      self.cardNum += 1
      self.nextCard += 1
      self.backCardImage.image = UIImage(named:self.imageList[self.nextCard])
  //(2)カードが残り2枚の時
  }else if self.cardNum == self.imageCount - 2{
        self.cardNum += 1
        self.backCard.alpha = 0
  //カードが残り1枚の時
  }else if self.cardNum == self.imageCount - 1{
        self.frontCard.alpha = 0
        print("カードがなくなりました。")
  }

3.リセットボタンについて

リセットボタンを押した後は、以下のように、初期値に戻せばリセット完了です。

rightInfo = []
leftInfo = []
cardNum = 0
nextCard = 1
frontCardImage.image = UIImage(named:imageList[cardNum])
backCardImage.image = UIImage(named:imageList[nextCard])
frontCard.alpha = 1
backCard.alpha = 1

GitHub

ソースコードは以下に挙げているので参考にしながら実装してみてください。

最後に

TinderのUIを実装しました。実装の際は結構頭を使うので、プログラミングの良い練習になるかと思います。

是非実装してみてください。

また、個人ブログ「とがみんブログ」も運営しているので、よければチェックしてみてください。

就職活動、心理学、脳科学、量子力学、とがみんの経験等、変なこと書いてます。