نحوه ساخت ویو کنترلر کاستوم برای ترانزیشن ها و انیمیشن ها در آی او اس

نحوه ساخت ویو کنترلر کاستوم برای ترانزیشن ها و انیمیشن ها در آی او اس

UIKit فریم ورک بسیار قدرتمندی است که روش های متنوع برای انتقال بین ویوهای مختلف را در اختیار توسعه دهندگان قرار می دهد. برخی از انیمیشن های موجود در UIKit شامل اسلایدینگ افقی، اسلایدینگ عمودی، محو شدن به صورت ضربدری و جمع شدن حلقه وار صفحه می شوند. به منظور ساخت یک طرح جذاب و خیره کننده به ترانزیشن های کاستوم برای ویو کنترلرها نیاز دارید و می توانید یک تجربه کاربری خاص و منحصر به فرد را در اختیار مشتریان خود قرار دهید. در این مطلب آموزشی نحوه ساخت ترانزیشن های کاستوم با بهره گیری از UIKit API به شما آموزش داده می شود.

پیش نیازها

API های استفاده شده برای ساخت ترانزیشن های کاستوم در نسخه 7 از آی او اس معرفی شدند، در این مطلب از Auto Layout و Swift 2 استفاده می شود و بدین منظور باید از +Xcode 7 یا بالاتر در OS X Yosemite خود استفاده کنید. پروژه اولیه از طریق لینک GitHub قابل دانلود می باشد.

1. کامپوننت های یک ترانزیشن کاستوم

در هنگام پیاده سازی و اجرای یک ترانزیشن کاستوم ویو کنترلر، اجزایی وجود دارند که باید از آنها آگاهی داشته باشید:

- animation cont

- رولر و یا همان انیمیتور

- transitioning delegate که یک ویو کنترلر است که تخصیص به آن صورت پذیرفته است

یک آبجکت animator مسئول تعیین مدت زمان ترانزیشن و منطق اصلی متحرک سازی ویوها می باشد. می توانید هر نوع آبجکتی را به عنوان کنترلر انیمیشن استفاده کنید، اما توجه داشته باشید که این آبجکت مطابق با پروتکل UIViewControllerAnimatedTransitioning باشد.

Transitioning delegate یا همان نماینده ترانزیشن، کنترلر انیمیشن را جهت استفاده در ترانزیشن کاستوم در اختیار قرار می دهد. آبجکت نماینده نیز باید مطابق با پروتکل UIViewControllerTransitioningDelegate باشد.

2. ساخت یک ترانزیشن کاستوم

پروژه اولیه را باز کرده و اپلیکیشن را به اجرا در آورید، با ضربه زدن بر روی دکمه Press to View ترانزیشن مدال استاندارد عمودی در آن استفاده شده است.

با انتخاب …New>File از منوی File یک فایل جدید بسازید و از بین گزینه های نمایش داده شده iOS>Source>Swift File را انتخاب کنید و نام فایل را CustomTransition بگذارید.

این فایل دربرگیرنده منطقی است که برای ترانزیشن کاستوم به آن نیاز دارید.

اول از همه به تعریف کلاس انیمیشن کنترلر می پردازیم که برای ترانزیشن کاستوم مورد استفاده قرار خواهد گرفت. کد زیر را به CustomTransition.swift بیفزایید.

import UIKit

enum TransitionType {

case Presenting, Dismissing

}

class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {

var duration: NSTimeInterval

var isPresenting: Bool

var originFrame: CGRect

init(withDuration duration: NSTimeInterval, forTransitionType type: TransitionType, originFrame: CGRect) {

self.duration = duration

self.isPresenting = type == .Presenting

self.originFrame = originFrame

super.init()

}

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {

return self.duration

}

}

یک شماره گذاری TransitionType تعریف شده است که برای ساخت آبجکت AnimationController مورد استفاده قرار می گیرد.

پس از آن کلاس AnimationController را با چند ویژگی تعریف می کنیم.

ویژگی duration برای تعیین مدت زمان انیمیشن مورد استفاده قرار می گیرد و همان مقدار بازگشتی از متد (:_)transitionDuration پروتکل UIViewCOntrollerAnimatedTransitioning است. لزومی برای متغییر بودن duration نیست، اما اگر بدین شکل استفاده شود تغییر آن راحت تر صورت می پذیرد. ویژگی های isPresenting و originFrame جهت ساخت انیمیشن مربوط به ترانزیشن مورد نظر استفاده خواهند شد.

در این مرحله Xcode خطایی را به شما نمایش می دهد، دلیل این امر عدم پیاده سازی متد الزامی از پروتکل UIViewContollerAnimatedTransitioning می باشد.

با آغاز شدن انیمیشن کاستوم، UIKit یک ویوی کانتینر را در اختیار شما قرار می دهد که محل اجرای انیمیشن ها برای ترانزیشن مورد نظر است. باید به طور دستی ویو کنترلری را که ترانزیشن به آن منتقل می شود در این ویوی کانتینر اضافه کنید. این ویوی کانتینر تنها در مدت ترانزیشن وجود دارد و با اتمام انیمیشن از سلسله مراتب ویو حذف خواهد شد.

در این مرحله قصد داریم تا یک انیمیشن کاستوم را پیاده سازی کنیم، برای این کار متد زیر را به کلاس AnimationController بیفزایید:

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {

let containerView = transitionContext.containerView()!

let fromView = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!.view

let toView = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!.view

let detailView = self.isPresenting ? toView : fromView

if self.isPresenting {

containerView.addSubview(toView)

} else {

containerView.insertSubview(toView, belowSubview: fromView)

}

detailView.frame.origin = self.isPresenting ? self.originFrame.origin : CGPoint(x: 0, y: 0)

detailView.frame.size.width = self.isPresenting ? self.originFrame.size.width : containerView.bounds.width

detailView.layoutIfNeeded()

for view in detailView.subviews {

if !(view is UIImageView) {

view.alpha = isPresenting ? 0.0 : 1.0

}

}

UIView.animateWithDuration(self.duration, animations: { () -> Void in

detailView.frame = self.isPresenting ? containerView.bounds : self.originFrame

detailView.layoutIfNeeded()

for view in detailView.subviews {

if !(view is UIImageView) {

view.alpha = self.isPresenting ? 1.0 : 0.0

}

}

}) { (completed: Bool) -> Void in

transitionContext.completeTransition(!transitionContext.transitionWasCancelled())

}

}

با کمک بازیابی ویو کانتینر از زمینه ترانزیشن و استفاده از متد ()containerView می توان این متد را آغاز کرد. با فراخوانی متد (:_)viewControllerForKey به ویوهای from و to دسترسی پیدا می کنیم و آنها را به ترتیب در UITransiotionContextFromViewControllerKey و UITransitionContextToControllerKey ارسال می کنیم.

در نسخه 8 و بالاتر از آی او اس با استفاده از متد (:_)ViewForKey و کلیدهای UITransiotionContextFromViewKey و UITransitionContextToViewKey به طور مستقیم قادر به دسترسی به ویوها می باشید.

در قسمت بدنه متد موردنظر با استفاده از UIView کنونی API انیمیشن دیتیل ویو بزرگ یا کوچک شده و متحرک می گردد.

متد (:_)completeTransition که در آبجکت مربوط به زمینه ترانزیشن صدا زده شد باید زمانی که انیمیشن به اتمام رسیده فراخوانی شود، چرا که سیستم باید از اتمام ترانزیشن ویو کنترلرها اطلاع پیدا کند. این متد یک پارمتر از نوع بولین را می گیرد و این پارامتر تعیین می کند که آیا ترانزیشن کامل شده است یا خیر.

با این نوع پیاده سازی متدی با عملکرد کامل برای انیمیشن ساخته شد و به منظور اجرای آن لازم است یک نماینده برای ترانزیشن راه اندازی کنیم.

3. تخصیص نماینده برای ترانزیشن

همانطور که قبلا نیز اشاره شد، وظیفه transitioning delegate در اختیار قرار دادن آبجکت انیمیشن کنترلر برای انتقال بین دو ویو کنترلر است. Transitioning delegate می تواند هر آبجکتی باشد، اما روش معمول برای انجام کار تعیین ویو کنترلر حاضر به عنوان نماینده است.

در CustomTransition.swift کد زیر را در قسمت زیرین تعریف کلاس AnimationController اضافه کنید:

extension ViewController: UIViewControllerTransitioningDelegate {

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

segue.destinationViewController.transitioningDelegate = self

}

func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {

return AnimationController(withDuration: 3.0, forTransitionType: .Dismissing, originFrame: self.image.frame)

}

func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {

return AnimationController(withDuration: 3.0, forTransitionType: .Presenting, originFrame: self.image.frame)

}

}

با اجرای این افزونه کلاس ViewController مطابق با  پروتکل UIViewControllerTransitioningDelegate ساخته و سه متد در آن جایگذاری شد. متد (:prepareForSegue(_:sender برای تعیین نمونه کنونی ViewController به عنوان DetailViewController مقصد آبجکت transitioningDelegate استفاده می شود.

دو متد دیگر یک آبجکت AnimationController می سازند که برای نمایش و رد ویو کنترلر با استفاده از اینیشیالایزری که قبلا تعریف کرده بودیم استفاده می شوند. چنانچه مقدار بازگشتی هریک از این متدها nil باشد، ترانزیشن استاندارد و پیش فرض ویو کنترلر برای آن استفاده می شود.

در این مرحله لازم است تا اپلیکیشن را به اجرا در آورید، حال اگر دکمه Press to View را بزنید باید آیکون Xcode تغییر اندازه داده و بزرگ شود و برچسب های دیگر به نمایش در آیند، به همین ترتیب با زدن دکمه Press to Close باید انیمیشن مشابه با ترتیبی برعکس را مشاهده کنید.

blog_16747_1

4. ساخت یک ترانزیشن تعاملی

به منظور بهبود عملکرد ترانزیشن کاستوم باید آن را تعاملی و ریسپانسیو کنیم، برای این کار به یک آبجکت نیاز دارید که مطابق با UIViewControllerInteractiveTransitioning باشد. در اینجا از کلاسی که توسط UIKit در اختیار قرار داده شده و با پروتکل مذکور یعنی UIPercentDrivenInteractiveTransition مطابقت دارد استفاده می کنیم.

به منظور تسهیل ارتباط بین ویو کنترلرها، DetailViewController.swift را باز کرده و ویژگی زیر را به کلاس DetailViewController اضافه کنید:

var rootViewController: ViewController!

سپس کد زیر را به متد (:_)didPanDown از کلاس DetailViewController بیفزایید:

@IBAction func didPanDown(sender: UIPanGestureRecognizer) {

let progress = sender.translationInView(self.view).y/self.view.frame.size.height

switch sender.state {

case .Began:

self.rootViewController.interactionController = UIPercentDrivenInteractiveTransition()

self.dismissViewControllerAnimated(true, completion: nil)

case .Changed:

self.rootViewController.interactionController?.updateInteractiveTransition(progress)

case .Ended:

if progress >= 0.5 {

self.rootViewController.interactionController?.finishInteractiveTransition()

} else {

self.rootViewController.interactionController?.cancelInteractiveTransition()

}

self.rootViewController.interactionController = nil

default:

self.rootViewController.interactionController?.cancelInteractiveTransition()

self.rootViewController.interactionController = nil

}

}

در متد (:_)didPanDown مقدار متغییر progress با در نظر گرفتن فاصله pan کردن کاربر با دیتیل ویو محاسبه می شود. اگر عملیات pan همین الان شروع شده است باید آبجکت کنترلر تعاملی را بسازیم و حذف کردن ویو کنترلر را آغاز نماییم. زمانی که جسچر pan در ویو حرکت می کند، کنترلر تعاملی با میزان پیشرفت ترانزیشن آپدیت می شود.

زمانی که pan به اتمام رسید، با استفاده از متدهای ()finishInteractiveTransition و ()cancelInteractiveTransition می توانیم به ترتیب ترانزیشن را به اتمام رسانده و یا کنسل کنیم.

در گام بعدی به CustomTransition.swift مراجعه کرده و متد (:prepareForSegue(_:sender در کلاس CiewController را با متد زیر جایگزین کنید:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

segue.destinationViewController.transitioningDelegate = self

(segue.destinationViewController as? DetailViewController)?.rootViewController = self

}

در (:prepareForSegue(_:sender دیتیل ویو کنترلر به ویو کنترلر روت دسترسی دارد.

در آخر لازم است متد زیر را به افزونه ViewController بیفزایید:

func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {

return self.interactionController

}

متد (:_)interactionControllerForDismissal مقدار interactionController از ویو کنترلر روت را باز می گرداند و در صورتی که این مقدار nil باشد از انیمیشن کاستوم به جای آن استفاده می شود.

می توان از کنترلر تعاملی برای نمایش ویو کنترلرها از طریق متد (:_)interactionControllerForPresentation  استفاده کرد.

اپلیکیشن را بیلد کرده و به اجرا در آورید، پس از نمایش دیتیل ویو کنترلر، با درگ به پایین صفحه بروید، در این صورت قادر به مشاهده ترانزیشن که مطابق با محل قرارگیری انگشت شما حرکت می کند خواهید بود.

جمع بندی

در این مطلب فرآیند ساخت ویو کنترلرهای تعاملی و کاستوم در آی او اس را فرا گرفته اید، می توان از این API ها برای هر نوع ترانزیشنی استفاده کرد.

 

http://code.tutsplus.com برگرفته از

اینها را هم بخوانید