Highly customizable drop-in solution for introduction views.

Overview

EAIntroView - simple iOS Introductions

CI Status Version Carthage compatible License Platform

ExampleImage1 ExampleImage2

This is highly customizable drop-in solution for introduction views. Some features (remember, most features are optional and can be turned off):

  • beautiful demo project to look on some examples
    • customizability is unlimited, one can make complex introView with animations and interactive pages, so do not limit yourself with existing examples
  • for each basic page:
    • background (with cross-dissolve transition between pages)
    • custom iOS7 motion effects (parallax) on background
    • title view (+ Y position)
    • title text (+ font, color and Y position)
    • description text (+ font, color, width and Y position)
    • subviews array (added to page after building default layout)
  • possibility to set your own custom view for page:
    • pageWithCustomView:
    • pageWithCustomViewFromNibNamed:
  • possibility to set block action on page events:
    • pageDidLoad
    • pageDidAppear
    • pageDidDisappear
  • many options to customize parent view:
    • swipe from last page to close
    • switching pages with one simple tap
    • custom background image or color
    • custom page control
    • custom skip button
    • pinned titleView (+ Y position, can be hidden on some pages)
  • delegate protocol to listen:
    • introDidFinish:
    • intro:pageAppeared:withIndex:
  • actions on IntroView:
    • setPages:
    • showInView:animateDuration:
    • hideWithFadeOutDuration:
    • setCurrentPageIndex:animated:
  • storyboard/IB support
  • and many more...

Installation

You can setup EAIntroView using Carthage, CocoaPods or completely manually.

Carthage

  1. Add EAIntroView to your project's Cartfile:

    github "ealeksandrov/EAIntroView"
  2. Run carthage update in your project directory.

  3. On your application targets’ “General” settings tab, in the “Linked Frameworks and Libraries” section, drag and drop EAIntroView.framework and EARestrictedScrollView.framework from the Carthage/Build/iOS/ folder on disk.

  4. On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script with the following contents:

    /usr/local/bin/carthage copy-frameworks

    add the paths to the frameworks under “Input Files”:

    $(SRCROOT)/Carthage/Build/iOS/EAIntroView.framework
    $(SRCROOT)/Carthage/Build/iOS/EARestrictedScrollView.framework

    and the paths to the copied frameworks to the “Output Files”:

    $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/EAIntroView.framework
    $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/EARestrictedScrollView.framework

CocoaPods

  1. Add EAIntroView to your project's Podfile:

    pod 'EAIntroView'
  2. Run pod update or pod install in your project directory.

Setting Up Manually

  1. Add EARestrictedScrollView header and implementation to your project (2 files total).

  2. Add EAIntroPage and EAIntroView headers and implementations to your project (4 files total).

  3. You can now use EAIntroView by adding the following import:

    import EAIntroView
    #import <EAIntroView/EAIntroView.h>

How To Use It

Sample project have many examples of customization. Here are only simple ones.

Step 1 - Build Pages

Each page created with [EAIntroPage page] class method. Then you can customize any property, all of them are optional. Another approach is to pass your own (can be nib), custom view in EAIntroPage, this way most other options are ignored.

// basic
EAIntroPage *page1 = [EAIntroPage page];
page1.title = @"Hello world";
page1.desc = sampleDescription1;
// custom
EAIntroPage *page2 = [EAIntroPage page];
page2.title = @"This is page 2";
page2.titleFont = [UIFont fontWithName:@"Georgia-BoldItalic" size:20];
page2.titlePositionY = 220;
page2.desc = sampleDescription2;
page2.descFont = [UIFont fontWithName:@"Georgia-Italic" size:18];
page2.descPositionY = 200;
page2.titleIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"title2"]];
page2.titleIconPositionY = 100;
// custom view from nib
EAIntroPage *page3 = [EAIntroPage pageWithCustomViewFromNibNamed:@"IntroPage"];
page3.bgImage = [UIImage imageNamed:@"bg2"];

Step 2 - Create Introduction View

Once all pages have been created, you are ready to create the introduction view. Just pass them in right order in the introduction view. You can also pass array of pages after IntroView's initialization, it will rebuild its contents.

EAIntroView *intro = [[EAIntroView alloc] initWithFrame:self.view.bounds andPages:@[page1,page2,page3,page4]];

Don't forget to set the delegate if you want to use any callbacks.

[intro setDelegate:self];

Step 3 - Show Introduction View

[intro showInView:self.view animateDuration:0.0];

Storyboard/IB

Since 1.3.0 EAIntroView supports init from IB. Since 2.0.0 EAIntroPage supports it too.

  1. Drop UIView to your IB document.
  2. Set its class to EAIntroView.
  3. Create IBOutlet property in your view controller: @property(nonatomic,weak) IBOutlet EAIntroView *introView;.
  4. Connect IBOutlet with EAIntroView in IB.
  5. Build array of pages (you can use pageWithCustomViewFromNibNamed: here with separate nibs for each page).
  6. Pass pages array to EAIntroView property in setPages:.

Author

Created and maintained by Evgeny Aleksandrov (@ealeksandrov).

License

EAIntroView is available under the MIT license. See the LICENSE.md file for more info.

Comments
  • Weird rotation in iPad?

    Weird rotation in iPad?

    So here is my code for creating the EAIntroView (using Swift)

        let titleColor = UIColor.blackColor()
        let descColor = UIColor.blueColor()
    
        let page1 = EAIntroPage()
        page1.title = "Some title"
        page1.desc = "Some deep"
        page1.titleColor = titleColor
        page1.descColor = descColor
        page1.bgImage = UIImage(named: "bg1")
    
        let page2 = EAIntroPage()
        page2.title = "page 2"
        page2.desc = "something again"
        page2.titleColor = titleColor
        page2.descColor = descColor
    
        let page3 = EAIntroPage()
        page3.title = "page 3"
        page3.desc = "again again again"
        page3.titleColor = titleColor
        page3.descColor = descColor
    
        let intro = EAIntroView(frame: self.view.bounds, andPages: [page1,page2,page3])
        intro.delegate = self
        intro.pageControl.pageIndicatorTintColor = UIColor.blackColor()
        intro.pageControl.currentPageIndicatorTintColor = UIColor.redColor()
    
        intro.showInView(self.view, animateDuration: 0.5)
    

    But on my iPad, the following display in iPad:

    untitled

    How can I fix it? Thanks!

    Bug Needs Investigation 
    opened by hesyifei 21
  • Transition to autolayout

    Transition to autolayout

    There are any plans to support layout constraints for all UI elements (e.g title and description)? For example, in an iPad could be useful to have a full support for portrait/landscape.

    Feature Request 
    opened by dorinsimina 20
  • Autolayout crash in iOS8

    Autolayout crash in iOS8

    To reproduce:

    1. Enable autolayout on IntroPage.xib
    2. Run demo project, select showIntroWithCustomViewFromNib
    3. Recieve crash:
    2015-02-25 22:21:25.829 EAIntroView[5215:1435025] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 5 beyond bounds [0 .. 4]'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x000000010c1f4f35 __exceptionPreprocess + 165
        1   libobjc.A.dylib                     0x000000010be8dbb7 objc_exception_throw + 45
        2   CoreFoundation                      0x000000010c0dff33 -[__NSArrayM objectAtIndex:] + 227
        3   UIKit                               0x000000010c87b5b1 _UIViewTopDownSubtreeTraversal + 193
        4   UIKit                               0x000000010ceacee6 -[UIView(UIConstraintBasedLayout_EngineDelegate) _invalidateSystemLayoutSizeFittingSizeAtEngineDelegateLevel] + 128
        5   Foundation                          0x000000010ba319bf -[NSISEngine tryToAddConstraintWithMarker:expression:integralizationAdjustment:mutuallyExclusiveConstraints:] + 915
        6   Foundation                          0x000000010bbbb0f8 -[NSLayoutConstraint _addLoweredExpression:toEngine:integralizationAdjustment:lastLoweredConstantWasRounded:mutuallyExclusiveConstraints:] + 275
        7   Foundation                          0x000000010ba2611a -[NSLayoutConstraint _addToEngine:integralizationAdjustment:mutuallyExclusiveConstraints:] + 220
        8   UIKit                               0x000000010cea9de5 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 474
        9   Foundation                          0x000000010ba33d6e -[NSISEngine withBehaviors:performModifications:] + 155
        10  UIKit                               0x000000010cea9beb __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
        11  UIKit                               0x000000010cea99fe -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
        12  UIKit                               0x000000010cea9ce4 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
        13  Foundation                          0x000000010ba33d6e -[NSISEngine withBehaviors:performModifications:] + 155
        14  UIKit                               0x000000010cea9beb __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
        15  UIKit                               0x000000010cea99fe -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
        16  UIKit                               0x000000010cea9ce4 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
        17  Foundation                          0x000000010ba33d6e -[NSISEngine withBehaviors:performModifications:] + 155
        18  UIKit                               0x000000010cea9beb __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
        19  UIKit                               0x000000010cea99fe -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
        20  UIKit                               0x000000010c8a568b -[UIScrollView _switchToLayoutEngine:] + 69
        21  UIKit                               0x000000010cea9ce4 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
        22  Foundation                          0x000000010ba33d6e -[NSISEngine withBehaviors:performModifications:] + 155
        23  UIKit                               0x000000010cea9beb __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
        24  UIKit                               0x000000010cea99fe -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
        25  UIKit                               0x000000010cea9ce4 __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke_2 + 217
        26  Foundation                          0x000000010ba33d6e -[NSISEngine withBehaviors:performModifications:] + 155
        27  UIKit                               0x000000010cea9beb __57-[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:]_block_invoke + 452
        28  UIKit                               0x000000010cea99fe -[UIView(AdditionalLayoutSupport) _switchToLayoutEngine:] + 197
        29  UIKit                               0x000000010cea9671 -[UIView(AdditionalLayoutSupport) _initializeHostedLayoutEngine] + 404
        30  UIKit                               0x000000010ce9e591 -[UIView(UIConstraintBasedLayout) _layoutEngine_windowDidChange] + 127
        31  UIKit                               0x000000010c8984a5 -[UIView(Internal) _didMoveFromWindow:toWindow:] + 207
        32  UIKit                               0x000000010c891112 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 125
        33  UIKit                               0x000000010c891086 -[UIView(Hierarchy) _postMovedFromSuperview:] + 437
        34  UIKit                               0x000000010c89af4b -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1604
        35  UIKit                               0x000000010cabfe84 -[UILayoutContainerView addSubview:] + 75
        36  EAIntroView                         0x000000010b93e14a -[EAIntroView showInView:animateDuration:withInitialPageIndex:] + 362
        37  EAIntroView                         0x000000010b93dfc9 -[EAIntroView showInView:animateDuration:] + 121
        38  EAIntroView                         0x000000010b9303a7 -[ViewController showIntroWithCustomViewFromNib] + 1879
        39  EAIntroView                         0x000000010b9326a4 -[ViewController tableView:didSelectRowAtIndexPath:] + 340
        40  UIKit                               0x000000010c90c393 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1293
        41  UIKit                               0x000000010c90c4d4 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 219
        42  UIKit                               0x000000010c847331 _applyBlockToCFArrayCopiedToStack + 314
        43  UIKit                               0x000000010c8471ab _afterCACommitHandler + 516
        44  CoreFoundation                      0x000000010c129dc7 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
        45  CoreFoundation                      0x000000010c129d20 __CFRunLoopDoObservers + 368
        46  CoreFoundation                      0x000000010c11fb53 __CFRunLoopRun + 1123
        47  CoreFoundation                      0x000000010c11f486 CFRunLoopRunSpecific + 470
        48  GraphicsServices                    0x00000001106f59f0 GSEventRunModal + 161
        49  UIKit                               0x000000010c824420 UIApplicationMain + 1282
        50  EAIntroView                         0x000000010b932843 main + 115
        51  libdyld.dylib                       0x000000010e9c7145 start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    

    Related: http://stackoverflow.com/questions/25878621/nsrangeexception-on-ios-8 Solution from SO:

    Turning AutoLayout off for all of my XIBs solved the issue.

    But: If you'll launch and close different intro example before opening autolaouyt one - it will work perfectly without crashing.

    Bug 
    opened by ealeksandrov 19
  • Button is not clickable in `titleView`

    Button is not clickable in `titleView`

    Here is my situation. I managed to display my button in the titleView. But somehow the button is not fired when I click on it. The titleView is created by my custom view from an xib file. I even tried it with a callback method but no luck How to fix this issue?

    Bug 
    opened by bangedorrunt 17
  • Fit titleIconView to page width

    Fit titleIconView to page width

    I was expecting the image to take up the available space. This is the code we used:

            let page1 = EAIntroPage()
            page1.title = NSLocalizedString("A party game", comment: "Intro screen 1 title")
            page1.desc = NSLocalizedString("For 3 to 12 players", comment: "Intro screen 1 detail")
            page1.titleIconView = UIImageView(image: UIImage(named: "help1"))
    

    This is what we got

    screen shot 2017-10-03 at 10 44 50 pm

    Currently best practice is this implementation: https://github.com/kolyvan/kxintro

    Feature Request 
    opened by fulldecent 11
  • Compile error in XCode while fetching EAIntroView through Pod

    Compile error in XCode while fetching EAIntroView through Pod

    "EARestrictedScrollView.h" not found error raised by XCode due to improper setting in "EAIntroView.h". Resolved after changing the import sentence from #import "EARestrictedScrollView.h" to #import "EARestrictedScrollView/EARestrictedScrollView.h" in EAIntroView.h

    Support 
    opened by joesong168 11
  • Show under navigation bar in Swift

    Show under navigation bar in Swift

    See screenshot: https://dl.dropboxusercontent.com/s/tuxgpwnhxecbncj/2015-01-25%20at%204.05%20PM.png?dl=0

    Related code in viewDidLoad:

            var page1 = EAIntroPage()
            page1.title = "Title 1"
            page1.desc = "Page 1 description"
    
            var page2 = EAIntroPage()
            page2.title = "Title 2"
            page2.desc = "Page 2 description"
    
            let rect = CGRectMake(0, 0, self.navigationController!.view.frame.width, self.navigationController!.view.frame.height)
            var introView = EAIntroView(frame:rect, andPages: [page1, page2])
            introView.showInView(self.navigationController!.view, animateDuration: 0.3)
    
    Bug 
    opened by allaire 8
  • Not working without autoresizing masks

    Not working without autoresizing masks

    One of the very recent release broke one my apps which uses a UISplitViewController:

    • the screen is black
    • the title and desc texts sit in the lower right corner.

    Not sure what changes broke it in EAIntroView, but last pull was from a few weeks ago and there was no issue then (and my app code has not changed in that area).

    I'll send a sample project by email.

    Bug 
    opened by caramdache 8
  • Have worked well in iOS 8?

    Have worked well in iOS 8?

    In iOS 8, EAIntroView works well too, except only one thing. That is a skipButton.

    I use auto layout to the skipButton, but it works like this image. Anyone know how can fix this skipButton in iOS 8?

    eaintroview_bug

    Support 
    opened by say8425 8
  • Description is gone in iOS 6.1

    Description is gone in iOS 6.1

    Hi

    Strange that the icon image view and title view is totally fine in iOS 6/7, but in iOS 6 the description is totally invisible. Not sure it's gone or just position isn't correct. Anyone encountered this before? Thanks.

    opened by ipeisong 8
  • IntroView as an IBOUTLET

    IntroView as an IBOUTLET

    Is it possible to have an init from Storyboard? So you could place the introView in the storybard and then in the viewcontroller's viewdidload make a call to set the pages?

    I guess this falls into the reload pages bit? I'm finding that by adding the introview in code it does not follow the autolayout setup in the storyboard?

    so for example if starting in landscape the images appear ok but when rotating to portrait the introview remains in portrait...

    opened by elpuerco63 8
  • Initial intro view not centered (iPhone X / landscape)

    Initial intro view not centered (iPhone X / landscape)

    Hello Evgeny,

    Thank you for your nice work.

    I have found a small glitch: on iPhone X + landscape (+ iOS 14), as the intro is started, the initial page is shifted to left or right with a distance equal to iPhone X notch height. Moreover, if you slide this first view by a small amount, you can "detach" the side of the ScrollView from the phone border.

    For example, if the phone notch is on the right, the first view is shifted initially to the right. Then, if slided (with a small impulse), you can center it, or detach to the right (from the left border) with the same distance.

    opened by hiworld75018 0
  • Support Swift Package Manager

    Support Swift Package Manager

    Please support Swift Package Manager.

    There is a guide on how to release modular projects which also includes making it work with SPM: https://github.com/fulldecent/swift5-module-template

    opened by fulldecent 1
  • Add seamless background parallax effect

    Add seamless background parallax effect

    The parallax feature of your EAIntroView I believe is not documented? Also, when you say parallax in EAIntroView, it's the iOS 7's parallax and not the scrolling parallax. Are we going to have this in the future? Thanks! G.,

    Feature Request 
    opened by glennposadas 3
  • Add more blocks for EAIntroPage lifecycle

    Add more blocks for EAIntroPage lifecycle

    about EAIntroPage you have three attribute, @property (nonatomic,copy) VoidBlock onPageDidLoad; @property (nonatomic,copy) VoidBlock onPageDidAppear; @property (nonatomic,copy) VoidBlock onPageDidDisappear;

    But it has limitations. I hope you can provide some other attributes, such as @property (nonatomic,copy) VoidBlock onPageWillAppear; @property (nonatomic,copy) VoidBlock onPageWillDisappear; like UIview life cycle,

    Being able to add some other attribute like UIView life cycle, would be appreciated.

    Thanks for the consideration.

    Feature Request 
    opened by sesameImmortals 2
Releases(2.13.0)
Owner
Evgeny Aleksandrov
Evgeny Aleksandrov
Swift Actors Introduction

Swift-Actors-Introduction Swift 5.5~ 並行処理におけるデータ整合やその他の不具合を防ぐための仕組み。 https://doc

Sho Emoto 0 Jan 3, 2022
OnboardKit - Customizable user onboarding for your UIKit app in Swift

OnboardKit Customizable user onboarding for your UIKit app in Swift Requirements Swift 5.0 Xcode 10 iOS 11.0+ Installation Carthage github "NikolaKire

Nikola Kirev 470 Dec 23, 2022
A UICollectionView backed drop-in component for introduction views

#GHWalkThrough - iOS App Walk through control This is simple and customizable drop-in solution for showing app walkthroughs or intros. Configurable to

Gnosis Hub 717 Dec 15, 2022
McPicker is a customizable, closure driven UIPickerView drop-in solution with animations that is rotation ready.

McPicker About McPicker is a UIPickerView drop-in solution with animations that is rotation ready. The more string arrays you pass, the more picker co

Kevin McGill 207 Dec 13, 2022
A highly customizable drop-in replacement for UISegmentedControl.

HMSegmentedControl A highly customizable drop-in replacement for UISegmentedControl, used by more than 22,000 apps, including TikTok, PayPal, Imgur an

Hesham Abd-Elmegid 3.9k Dec 21, 2022
Highly configurable iOS Alert Views with custom content views

NYAlertViewController NYAlertViewController is a replacement for UIAlertController/UIAlertView with support for content views and UI customization. Fe

Nealon Young 609 Nov 20, 2022
Newly is a drop in solution to add Twitter/Facebook/Linkedin style, new updates/tweets/posts available button

Newly is a drop in solution to add Twitter/Facebook/Linkedin style, new updates/tweets/posts available button. It can be used to notify user about new content availability and can other actions can be triggers using its delegate method.

Dhiraj Rajendra Jadhao 197 Sep 22, 2022
A drop-in universal solution for moving text fields out of the way of the keyboard in iOS

TPKeyboardAvoiding A drop-in universal solution for moving text fields out of the way of the keyboard in iOS. Introduction There are a hundred and one

Michael Tyson 5.8k Dec 26, 2022
PRGTipView is a drop-in solution for adding onboarding tips to your apps

PRGTipView PRGTipView is a drop-in solution for adding onboarding tips to your apps. It supports: Title, detail and dismissal button Give focus on a p

Iannis Spiropoulos 25 Aug 12, 2022
An unofficial version of the Sandwiches app and pre-built materials similar to those used in the Introduction to SwiftUI session video from WWDC20

Unofficial Sandwiches The WWDC20 Session Introduction to SwiftUI provides a tutorial-like walk-through of building a list-detail SwiftUI app from scra

James Dempsey 94 Feb 11, 2022
Swift IOS App introduction project

Swifty Companion This project aims to introduce you to the development of iOS application. About With the help of 42 API, get a student's profile deta

null 0 Nov 13, 2021
An introduction to using Swift's new concurrency features in SwiftUI

SwiftUI Concurrency Essentials An introduction to using Swift's new concurrency features in SwiftUI Discuss with me · Report Bug · Request Feature Art

Peter Friese 80 Dec 14, 2022
Final project of Introduction to Swift course

Final project of Introduction to Swift course This project summarizes the concepts viewed on class, from simple variable creations, loops and conditio

Fernando López López 0 Dec 12, 2021
Swift Actors Introduction

Swift-Actors-Introduction Swift 5.5~ 並行処理におけるデータ整合やその他の不具合を防ぐための仕組み。 https://doc

Sho Emoto 0 Jan 3, 2022
It is a highly configurable iOS library which allows easy styling with built in styles as well as extra header and footer views so that you can make extremely unique alerts and action sheets.

 CFAlertViewController CFAlertViewController is a library that helps you display and customise Alerts, Action Sheets, and Notifications on iPad and i

Crowdfire Inc. 1.1k Dec 18, 2022
JTChartView is the new lightweight and fully customizable solution to draw a chart

JTChartView JTChartView is the new lightweight and fully customizable solution to draw a curve and fill the space underneath it with a gradient. The r

Jakub Truhlář 124 Sep 7, 2022
This component allows for the transfer of data items between collection views through drag and drop

Drag and Drop Collection Views Written for Swift 4.0, it is an implementation of Dragging and Dropping data across multiple UICollectionViews. Try it

Michael Michailidis 508 Dec 19, 2022
This component allows for the transfer of data items between collection views through drag and drop

Drag and Drop Collection Views Written for Swift 4.0, it is an implementation of Dragging and Dropping data across multiple UICollectionViews. Try it

Michael Michailidis 508 Dec 19, 2022
SwiftCharts - Easy to use and highly customizable charts library for iOS

SwiftCharts Easy to use and highly customizable charts library for iOS Features: Bars - plain, stacked, grouped, horizontal, vertical Scatter Lines (s

Ivan Schütz 2.4k Jan 4, 2023
Highly customizable Action Sheet Controller with Assets Preview written in Swift

PPAssetsActionController Play with me ▶️ ?? If you want to play with me, just tap here and enjoy! ?? ?? Show me ?? Try me ?? The easiest way to try me

Pavel Pantus 72 Feb 4, 2022