In CosmicMind / Material SnackbarController, how do I start (show) the snackbar? - ios

In CosmicMind / Material library, how do I start (show) the snackbar?
I have tried to prepare the snackbarController and then show it whenever the user clicks on a button.
As shown in their example:
private var undoButton: FlatButton!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
prepareSnackbar()
animateSnackbar()
}
#IBAction func loginBtnTapped(_ sender: AnyObject) {
sc?.show(vc: UIViewControlle, sender: Any)//doesn't show
more code... (which works)
}
private func prepareUndoButton() {
undoButton = FlatButton(title: "Undo", titleColor: Color.yellow.base)
undoButton.pulseAnimation = .backing
undoButton.titleLabel?.font = RobotoFont.regular(with: 14)
}
private func prepareSnackbar() {
guard let sc = snackbarController else {
return
}
sc.snackbar.text = "Reminder saved."
sc.snackbar.rightViews = [undoButton]
}
private func animateSnackbar() {
guard let sc = snackbarController else {
return
}
_ = sc.animate(snackbar: .visible, delay: 1)
_ = sc.animate(snackbar: .hidden, delay: 4)
}
So I did try it on an empty project and the snackbar still doesn't work. Could you please point out what I am doing wrong?
import Foundation
import UIKit
import Material
class MainViewController: UIViewController {
private var undoButton: FlatButton!
open override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Color.red.accent1
prepareUndoButton()
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//prepareSnackbar()
//animateSnackbar()
}
private func prepareUndoButton() {
undoButton = FlatButton(title: "Undo", titleColor: Color.yellow.base)
undoButton.pulseAnimation = .backing
undoButton.titleLabel?.font = RobotoFont.regular(with: 14)
}
private func prepareSnackbar() {
guard let sc = snackbarController else {
return
}
sc.snackbar.text = "Reminder saved."
sc.snackbar.rightViews = [undoButton]
}
private func animateSnackbar() {
guard let sc = snackbarController else {
return
}
_ = sc.animate(snackbar: .visible, delay: 1)
_ = sc.animate(snackbar: .hidden, delay: 4)
}
#IBAction func testBtn(_ sender: AnyObject) {
print("TEST TEST TEST")
prepareSnackbar()
animateSnackbar()
}
}

If you notice in the viewDidAppear function you have an animateSnackbar call, which calls the lines
_ = sc.animate(snackbar: .visible, delay: 1)
_ = sc.animate(snackbar: .hidden, delay: 4)
You can basically use the animateSnackbar function in your button handler, like so:
#IBAction func loginBtnTapped(_ sender: AnyObject) {
animateSnackbar()
}
That's it. There are two animations playing, one to show and one to hide the snackbar. Set the delay you would like to have them appear and hide automatically.
You will probably want to remove the animateSnackbar call from the viewDidAppear method, as that was put there for the example.

Related

How to use SCNView as a SubView of ARView?

I'm using ARKit-CoreLocation library to present POIs in AR World, in iOS 14. But the thing is, I am not able to use ARCL's SceneLocationView because it is SCNView. So when I add it as a subview, it overlaps my ARView contents and creates a new ARSession, leaving my ARView in the background.
Code:
extension RealityKitViewController {
typealias Context = UIViewControllerRepresentableContext<RealityKitViewControllerRepresentable>
}
class RealityKitViewController: UIViewController {
let sceneLocationView = SceneLocationView()
let arView = ARView(frame: .zero)
let context : Context
let pins: [Pin]
var currentLocation : CLLocation? {
return sceneLocationView.sceneLocationManager.currentLocation
}
init (_ context : Context, pins: [Pin]) {
self.context = context
self.pins = pins
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func makeArView()
{
// Start AR session
let session = arView.session
let config = ARWorldTrackingConfiguration()
config.planeDetection = [.horizontal, .vertical]
session.run(config)
// Add coaching overlay
let coachingOverlay = ARCoachingOverlayView()
coachingOverlay.session = session
coachingOverlay.goal = .horizontalPlane
coachingOverlay.delegate = context.coordinator
arView.addSubview(coachingOverlay)
arView.debugOptions = [.showFeaturePoints, .showAnchorOrigins, .showAnchorGeometry]
// Handle ARSession events via delegate
context.coordinator.view = arView
session.delegate = context.coordinator
}
override func viewDidLoad() {
super.viewDidLoad()
// probably problem here
sceneLocationView.frame = view.bounds
arView.frame = sceneLocationView.bounds
sceneLocationView.addSubview(arView)
view.addSubview(sceneLocationView)
addPins()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
sceneLocationView.frame = view.bounds
}
override func viewWillAppear(_ animated: Bool) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
super.viewWillAppear(animated)
self.sceneLocationView.run()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
sceneLocationView.pause()
}
func addPins() {
guard let currentLocation = currentLocation, currentLocation.horizontalAccuracy < 16 else {
return DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.addPins()
}
}
self.pins.forEach { pin in
guard pin.isLocation else { return }
guard let location = pin.location else { return assertionFailure() }
guard let image = UIImage(named: pin.image) else { return assertionFailure() }
let node = LocationAnnotationNode(location : location, image: image)
node.scaleRelativeToDistance = true
sceneLocationView.addLocationNodeWithConfirmedLocation(locationNode: node)
}
}
}
// if you want to test it, you can try to place these pins to a location where you can easily get coordinates from Google Earth.
struct RealityKitViewControllerRepresentable : UIViewControllerRepresentable {
let pins = [Pin(image: "test", location: CLLocation(coordinate: CLLocationCoordinate2D(latitude: 0.03275742958, longitude: 0.32827424), altitude: 772.1489524841309), isLocation: true)]
#Binding var arActivate : Bool
func makeUIViewController(context: Context) -> RealityKitViewController {
let viewController = RealityKitViewController(context, pins: pins)
return viewController
}
func updateUIViewController(_ uiViewController: RealityKitViewController, context: Context) {
}
func makeCoordinator() -> Coordinator {
Coordinator()
}
}
class Coordinator: NSObject, ARSessionDelegate {
weak var view: ARView?
}

ios Swift Protocol Data

I don't use storyboards.
I want to send protocol data using #objc button action.
However, the sent view controller does not run the protocol function.
May I know what the reason is?
In fact, there's a lot more code.
Others work, but only protocol functions are not executed.
The didUpdataChampion function is
Data imported into a different protocol.
I have confirmed that there is no problem with this.
protocol MyProtocolData {
func protocolData(dataSent: String)
func protocolCount(dataInt: Int)
}
class PickViewController: UIViewController,ChampionManagerDelegate{
static let identifier = "PickViewController"
var count = 0
var urlArray = [URL]()
var pickDelegate : MyProtocolData?
override func viewDidLoad() {
super.viewDidLoad()
champions.riot(url: "myURL")
}
#objc func topHand(){
pickDelegate?.protocolData(dataSent: "top")
print(count)
pickDelegate?.protocoCount(dataInt: count)
let cham = ChampViewController()
cham.modalPresentationStyle = .fullScreen
present(cham, animated: true, completion: nil)
}
//Data imported to another protocol
func didUpdataChampion(_ championManager: ChampionManager, champion: [ChampionRiot]) {
print(#function)
count = champion.count
for data in champion {
let id = data.id
guard let url = URL(string: "https://ddragon.leagueoflegends.com/cdn/11.16.1/img/champion/\(id).png") else { return }
urlArray.append(url)
count = urlArray.count
}
}
func didFailWithError(error: Error) {
print(error)
}
}
class ChampViewController: UIViewController,MyProtocolData {
var pickData = ""
var arrayCount = 0
override func viewDidLoad() {
super.viewDidLoad()
}
func protocolData(dataSent: String) {
print(#function)
pickData = dataSent
print(pickData)
}
func protocoCount(dataInt: Int) {
print(#function)
arrayCount = dataInt
print(arrayCount)
}
}
i don't see full code, for instance how you call bind to topHand(), my advice is:
check that topHand - is called
check that pickDelegate isn't nil inside topHand
Create Object fo your PickViewController class and set its delegate to self.
var yourObj = PickViewController()
override func viewDidLoad() {
super.viewDidLoad()
yourObj.delegate = self
}

Calling function inside function in another function

I'm new in iOS Programming, and I had this problem. Let's say I have these two function:
class BaseViewController: UIViewController, ErrorMessageDelegate {
var uiView = UIView();
var viewErrorMessage:ErrorMessage!
func refresh(_sender: AnyObject) {
print("testing")
}
func getErrorMessage(message:String) {
super.viewDidLoad()
Dialog.dismiss()
ErrorMessage.message = message
viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as! ErrorMessage
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
func removeSubView() {
viewErrorMessage.removeFromSuperview()
}
}
}
I want to call function removeSubView inside function refresh. I had to do that because I need to override refresh function to my subclass. And I need to put the function removeSubView in getErrorMessage because I should to. Does anyone know how to do that?
Please refer below code. It will help you to resolve the issue.
Code:
class BaseViewController: UIViewController, ErrorMessageDelegate {
var uiView = UIView();
var viewErrorMessage:ErrorMessage!
func refresh(_sender: AnyObject) {
removeSubView()
}
func getErrorMessage(message:String) {
super.viewDidLoad()
Dialog.dismiss()
ErrorMessage.message = message
viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as! ErrorMessage
viewErrorMessage.delegate = self
self.view.addSubview(viewErrorMessage)
}
func removeSubView() {
viewErrorMessage.removeFromSuperview()
}
}
Yes, that is possible
func a() {
c()
}
func b() {
c()
}
func c() {
print("hello world")
}
no it is not possible - but I wonder why you would do that?

Customize FUIAuthPickerViewController

How can I customize the Firebase UI Auth Picker controller with custom buttons, custom actions, background, loader etc..
I already try to subclass the FUIAuthPickerViewController but we can't access to login buttons
This is how you can create your own class of FUIAuthPickerViewController:
Create FUICustomLoginController.swift with:
import UIKit
import FirebaseUI
import FirebaseAuth
class FUICustomLoginController: ViewController {
var authUI: FUIAuth! = FUIAuth.defaultAuthUI()
var auth: Auth = Auth.auth()
private func didSignIn(auth: AuthCredential?, error: Error?, callBack: AuthResultCallback?) {
let callBack: (AuthDataResult?, Error?) -> Void = { [unowned self] result, error in
callBack?(result?.user, error)
self.authUI.delegate?.authUI?(self.authUI, didSignInWith: result, error: error)
}
if let auth = auth {
self.auth.signInAndRetrieveData(with: auth, completion: callBack)
} else if let error = error {
callBack(nil, error)
}
}
func signIn<T: FUIAuthProvider>(type: T.Type, defaultValue: String? = nil) {
try? self.authUI.signOut() // logout from google etc..
self.authUI.providers.first(where: { $0 is T })?.signIn(withDefaultValue: defaultValue, presenting: self, completion: self.didSignIn)
}
}
Subclass your controller from FUICustomLoginController:
class LoginPickerController: FUICustomLoginController {
override func viewDidLoad() {
super.viewDidLoad()
// Customize authUI if needed
//self.authUI.providers = ...
self.authUI.delegate = self
}
#IBAction func loginFacebook(_ sender: Any) {
self.signIn(type: FUIFacebookAuth.self)
}
#IBAction func loginGoogle(_ sender: Any) {
self.signIn(type: FUIGoogleAuth.self)
}
#IBAction func loginPhone(_ sender: Any) {
self.signIn(type: FUIPhoneAuth.self)
}
}
extension LoginPickerController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
// perform login actions
}
}
You can customize the default buttons, add images etc.. (a working hack )
class SignInViewController: FUIAuthPickerViewController {
weak var delegate: signInProtocol?
// Unhashed nonce.
fileprivate var currentNonce: String?
var backgView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
for each in view.subviews[0].subviews[0].subviews[0].subviews {
if let button = each as? UIButton {
button.layer.cornerRadius = 20.0
button.layer.masksToBounds = true
///do any other button customization here
}
}
///add background image
let scrollView = view.subviews[0]
scrollView.backgroundColor = .clear
let contentView = scrollView.subviews[0]
contentView.backgroundColor = .clear
let background = UIImage(named: "imagename")
let backgroundImageView = UIImageView(image: background)
backgroundImageView.contentMode = .scaleToFill
view.insertSubview(backgroundImageView, at: 0)
}
}

iOS today extension causes Program ended with exit code: 0

I'm using Xcode 8.0, Swift 3.
I'm making today extension showing text and image, but frequently cause this message and today extension does not work.
rarely work.
Program ended with exit code: 0
I saved data in realm, and today extension using the data(string, image)
is it cause a memory limit? so, how can i derease memory about today extension using??
My extension code:
class Information: Object {
dynamic var Name = ""
dynamic var Image : NSData?
override class func primaryKey() -> String {
return "Name"
}
}
class TodayViewController: UIViewController, NCWidgetProviding {
var realm : Realm?
var results : Results<Information>?
var index = 0
#IBOutlet var NameLabel: UILabel!
#IBOutlet var ImageView: UIImageView!
#IBAction func leftAction(_ sender: UIButton) {
guard index == 0 else {
index -= 1
loadData(index: index)
return
}
}
#IBAction func rightAction(_ sender: UIButton) {
guard index == (results?.count)! - 1 else {
index += 1
loadData(index: index)
return
}
}
override func viewDidLoad() {
super.viewDidLoad()
setRealmFileURL()
if #available(iOSApplicationExtension 10.0, *) {
extensionContext?.widgetLargestAvailableDisplayMode = .expanded
}else{
preferredContentSize = CGSize(width: 0, height: 250)
}
// Do any additional setup after loading the view from its nib.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
realm = try! Realm()
results = try! Realm().objects(Information.self)
loadData(index: index)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
private func widgetPerformUpdate(completionHandler: ((NCUpdateResult) -> Void)) {
// Perform any setup necessary in order to update the view.
// If an error is encountered, use NCUpdateResult.Failed
// If there's no update required, use NCUpdateResult.NoData
// If there's an update, use NCUpdateResult.NewData
loadData(index: index)
completionHandler(NCUpdateResult.newData)
}
func loadData(index: Int){
guard results?.count == 0 else {
let objects = results?[index]
NameLabel.text = objects?.Name
ImageView.image = UIImage(data: (objects?.Image)! as Data, scale: 0.1)
return
}
}
#available(iOSApplicationExtension 10.0, *)
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {
preferredContentSize = CGSize(width: 0, height: 250)
}
func setRealmFileURL(){
var config = Realm.Configuration(encryptionKey: getKey() as Data)
let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.xxx")
let realmPath = directory?.appendingPathComponent("xxx.realm")
config.fileURL = realmPath
Realm.Configuration.defaultConfiguration = config
}
}
mostly it is a problem with memory. The Widget will get cut off if it consumes to much.
Unless something in the app needs to change, don't use
completionHandler(NCUpdateResult.NewData)
instead use
completionHandler(NCUpdateResult.noData)

Resources