private func showAlert(withMessage message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default) { alertAction in
alertController.dismiss(animated: true, completion: nil)
})
self.present(alertController, animated: true, completion: nil)
}
lunes, 18 de diciembre de 2017
miércoles, 13 de diciembre de 2017
iOS: Tethering an Android device to an iPhone
1) On an Android powered phone, enter the Tethering and Hotspot Menu.
2) Select the option to enable Bluetooth Tethering.
3) Enable Bluetooth on the phone.
4) In the Bluetooth menu, make the phone discoverable by tapping the top message.
5) On the iPad, turn the Bluetooth on in Settings.
6) When the phone appears on the list of devices, Tap to connect.
7) Once connected, there will be a tethering icon in the top left of the screen.
8) The iPad now has internet access through the phones mobile data connection.
2) Select the option to enable Bluetooth Tethering.
3) Enable Bluetooth on the phone.
4) In the Bluetooth menu, make the phone discoverable by tapping the top message.
5) On the iPad, turn the Bluetooth on in Settings.
6) When the phone appears on the list of devices, Tap to connect.
7) Once connected, there will be a tethering icon in the top left of the screen.
8) The iPad now has internet access through the phones mobile data connection.
jueves, 30 de noviembre de 2017
iOS: Facebook login
1) Create fb application and install sdk steps
pod 'FBSDKCoreKit'
pod 'FBSDKShareKit'
pod 'FBSDKLoginKit'
2) In your app delegate:
Objective C
pod 'FBSDKCoreKit'
pod 'FBSDKShareKit'
pod 'FBSDKLoginKit'
2) In your app delegate:
Objective C
import FBSDKCoreKit
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
...
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let handled = FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
return handled
}
Swift
import FBSDKCoreKit
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
...
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let handled = FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
return handled
}
Swift
import FBSDKCoreKit
...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
return true
}
...
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let handled = FBSDKApplicationDelegate.sharedInstance().application(app, open: url, sourceApplication: options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String, annotation: options[UIApplicationOpenURLOptionsKey.annotation])
return handled
}
3) Add login button
Add default facebook button
Swift
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email"]
loginButton.delegate = self
loginButton.center = view.center
...
extension ViewController: FBSDKLoginButtonDelegate {
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if let token = result?.token?.tokenString {
NSLog("Token: %@", token)
} else {
NSLog("Error: %@", error.localizedDescription)
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
NSLog("Logged out from facebook")
}
}
Add custom button
Swift
Add default facebook button
Swift
let loginButton = FBSDKLoginButton()
loginButton.readPermissions = ["public_profile", "email"]
loginButton.delegate = self
loginButton.center = view.center
...
extension ViewController: FBSDKLoginButtonDelegate {
func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {
if let token = result?.token?.tokenString {
NSLog("Token: %@", token)
} else {
NSLog("Error: %@", error.localizedDescription)
}
}
func loginButtonDidLogOut(_ loginButton: FBSDKLoginButton!) {
NSLog("Logged out from facebook")
}
}
Add custom button
Swift
FBSDKLoginManager().logIn(withReadPermissions: ["email","public_profile"], from: self) { (result, error) in
if let let tokenString = result?.token?.tokenString {
} else {
// error
}
}
if let let tokenString = result?.token?.tokenString {
} else {
// error
}
}
4) In you .plist add
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb{facebook_app_id}</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>{facebook_app_id}</string>
<key>FacebookDisplayName</key>
<string>ROMWOD</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>fb{facebook_app_id}</string>
</array>
</dict>
</array>
<key>FacebookAppID</key>
<string>{facebook_app_id}</string>
<key>FacebookDisplayName</key>
<string>ROMWOD</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb-messenger-api</string>
<string>fbauth2</string>
<string>fbshareextension</string>
</array>
lunes, 13 de noviembre de 2017
iOS: TextView with placeholder text
class TextViewWithPlaceholder: UITextView {
private var _placeholderTextColor: UIColor = UIColor.lightGray
@IBInspectable var placeholderTextColor: UIColor {
set {
_placeholderTextColor = newValue
textColor = newValue
}
get {
return _placeholderTextColor
}
}
@IBInspectable var placeholderText: String? {
didSet {
if text.isEmpty {
text = placeholderText
}
}
}
private var initialTextColor: UIColor?
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
initialTextColor = textColor
text = placeholderText
NotificationCenter.default.addObserver(self, selector: #selector(didBeginEditing(_:)), name: UITextView.textDidBeginEditingNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(didEndEditing(_:)), name: UITextView.textDidEndEditingNotification, object: self)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func didBeginEditing(_ notification: NSNotification) {
if let textView = notification.object as? TextViewWithPlaceholder, textView == self, text == placeholderText {
text = ""
textColor = initialTextColor
}
}
@objc func didEndEditing(_ notification: NSNotification) {
if let textView = notification.object as? TextViewWithPlaceholder, textView == self, text.isEmpty {
text = placeholderText
textColor = placeholderTextColor
}
}
}
miércoles, 18 de octubre de 2017
ionic: Buttons
<button
// (click)="onClick()"
// [navPush]="yourPage"
ion-button
// color="primary"
// outline | clear | round
// block (from inline element to block element)
// small | medium | large
// icon-only
// icon-left | icon-right
>
Button name
// <ion-icon name="icon-name"></ion-icon>
</button>
// (click)="onClick()"
// [navPush]="yourPage"
ion-button
// color="primary"
// outline | clear | round
// block (from inline element to block element)
// small | medium | large
// icon-only
// icon-left | icon-right
>
Button name
// <ion-icon name="icon-name"></ion-icon>
</button>
jueves, 28 de septiembre de 2017
ionic: Color
src/theme/variables.scss
In here define your colors inside $colors map:
$colors: (
primary: #488aff,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
...
myColor: #ff0000,
);
custom_scss.scss
.my-class {
...
background-color: color($colors, myColor);
}
In here define your colors inside $colors map:
$colors: (
primary: #488aff,
secondary: #32db64,
danger: #f53d3d,
light: #f4f4f4,
dark: #222,
...
myColor: #ff0000,
);
custom_scss.scss
.my-class {
...
background-color: color($colors, myColor);
}
martes, 26 de septiembre de 2017
ionic: Menu
app.html
<ion-menu [content]="id_name">
<ion-header>
<ion-toolbar>
<ion-title>menu_name</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion-item (click)="loadPage(page1)">
<ion-icon name="menu_item_1" item-left></ion-icon>
item_1
</button>
<button ion-item (click)="loadPage(page2)">
<ion-icon name="menu_item_2" item-left></ion-icon>
item_2
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #id_name></ion-nav>
app.component.ts
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage = RootPage;
page1 = Page1;
page2 = Page2;
@ViewChild('nav') nav: NavController; // Because the menu is inside the ion-nav
....
onLoad(page: any) {
this.nav.setRoot(page);
this.menuController.close();
}
}
<ion-menu [content]="id_name">
<ion-header>
<ion-toolbar>
<ion-title>menu_name</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion-item (click)="loadPage(page1)">
<ion-icon name="menu_item_1" item-left></ion-icon>
item_1
</button>
<button ion-item (click)="loadPage(page2)">
<ion-icon name="menu_item_2" item-left></ion-icon>
item_2
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #id_name></ion-nav>
app.component.ts
@Component({
templateUrl: 'app.html'
})
export class MyApp {
rootPage = RootPage;
page1 = Page1;
page2 = Page2;
@ViewChild('nav') nav: NavController; // Because the menu is inside the ion-nav
....
onLoad(page: any) {
this.nav.setRoot(page);
this.menuController.close();
}
}
your_page.html
<ion-header>
<ion-navbar>
<ion-buttons start>
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
</ion-buttons>
<ion-title>your_page</ion-title>
</ion-navbar>
</ion-header>
...
ionic: Theming
In theme folder, in variables.scss:
1) Redefine a one:
$content-padding: 8px;
2) Add one, inside a map, for instance, colors or outside of it.
Inside:
$colors: ( primary: #488aff, secondary: #32db64, danger: #f53d3d, light: #f4f4f4, dark: #222, myColor: #f2f2f2 );
Outside:
$myColor: #f2f2f2
1) Redefine a one:
$content-padding: 8px;
2) Add one, inside a map, for instance, colors or outside of it.
Inside:
$colors: ( primary: #488aff, secondary: #32db64, danger: #f53d3d, light: #f4f4f4, dark: #222, myColor: #f2f2f2 );
Outside:
$myColor: #f2f2f2
ionic: View hooks
| willEnter | Observable, fired when Component is about to become active |
| didEnter | Observable, fired when Component has become active |
| willLeave | Observable, fired when Component is about to become inactive |
| didLeave | Observable, fired when Component has become inactive |
| willUnload | Observable, fired when Component has been destroyed |
| onWillDismiss | Observable, fired when Component will be dismissed |
| onDidDismiss | Observable, fired when Component was dismissed |
lunes, 25 de septiembre de 2017
ionic: Import data
your_data.ts
export default / data_name [
// Json object
]
to use it, import it:
import any_name (if default) / data_name from 'your_data_relative_location';
...
ngOnInit() {
this.quoteCollection = quotes;
}
export default / data_name [
// Json object
]
to use it, import it:
import any_name (if default) / data_name from 'your_data_relative_location';
...
ngOnInit() {
this.quoteCollection = quotes;
}
viernes, 22 de septiembre de 2017
ionic: Interface
export interface interface_name {
// definition
}
Note: Can by used to import data.
To use it import it in your file:
import { interface_name } from 'interface_relative_location';
// definition
}
Note: Can by used to import data.
To use it import it in your file:
import { interface_name } from 'interface_relative_location';
miércoles, 30 de agosto de 2017
ionic: Icons
Icons collection:
http://ionicframework.com/docs/ionicons/
Example:
<ion-tab [root]="favoritesPage" tabTitle="Favorites" tabIcon="star"></ion-tab>
http://ionicframework.com/docs/ionicons/
Example:
<ion-tab [root]="favoritesPage" tabTitle="Favorites" tabIcon="star"></ion-tab>
martes, 29 de agosto de 2017
ionic: Navigate from one page to another passing parameters
One page
onepage.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { UserPage } from './otherpage';
@Component({
selector: 'page-one',
templateUrl: 'one.html'
})
export class OnePage {
constructor (private navController: NavController) {
}
onLoad(someParameter: string) {
this.navController.push(OtherPage, {parameter1: someParameter});
}
}
onepage.html
<ion-header>
<ion-navbar>
<ion-title>One Page</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<button ion-button (click)="onLoad('Value1')"> Value 1 </button>
<hr>
<button ion-button (click)="onLoad('Value2')"> Value 2 </button>
</ion-content>
Other page
otherpage.ts
import { Component } from '@angular/core';
import { NavParams } from 'ionic-angular';
@Component({
selector: 'page-other',
templateUrl: 'other.html'
})
export class OtherPage {
parameter: string;
constructor (private navParams: NavParams) {
}
ngOnInit() {
this.name = this.navParams.get('parameter1');
}
}
otherpage.html
<ion-header>
<ion-navbar>
<ion-title>{{parameter}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>{{parameter}}</p>
</ion-content>
Add onepage and other page to app.module.ts.
onepage.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { UserPage } from './otherpage';
@Component({
selector: 'page-one',
templateUrl: 'one.html'
})
export class OnePage {
constructor (private navController: NavController) {
}
onLoad(someParameter: string) {
this.navController.push(OtherPage, {parameter1: someParameter});
}
}
onepage.html
<ion-header>
<ion-navbar>
<ion-title>One Page</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<button ion-button (click)="onLoad('Value1')"> Value 1 </button>
<hr>
<button ion-button (click)="onLoad('Value2')"> Value 2 </button>
</ion-content>
otherpage.ts
import { Component } from '@angular/core';
import { NavParams } from 'ionic-angular';
@Component({
selector: 'page-other',
templateUrl: 'other.html'
})
export class OtherPage {
parameter: string;
constructor (private navParams: NavParams) {
}
ngOnInit() {
this.name = this.navParams.get('parameter1');
}
}
otherpage.html
<ion-header>
<ion-navbar>
<ion-title>{{parameter}}</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<p>{{parameter}}</p>
</ion-content>
Add onepage and other page to app.module.ts.
ionic: Add a page
Automatic way
1) You can do it “automatically”
ionic generate page users
2) Modify app.module.ts and add your page to declarations and entryComponents don’t forget to add the import.
3) Link from another existing page, don’t forget to include the import here as well.
Manual way
0) Create a folder (if needed)
1) Create a file <custom_page>.ts
import { Component } from '@angular/core';
@Component({
selector: 'page-custom',
templateUrl: 'custom.html';
})
export class CustomPage {
}
2) Create a <custom>.html
<ion-header>
<ion-navbar>
<ion-title>My title</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
</ion-content>
2) Modify app.module.ts and add your page to declarations and entryComponents don’t forget to add the import.
4) Link from another existing page, don’t forget to include the import here as well.
1) You can do it “automatically”
ionic generate page users
2) Modify app.module.ts and add your page to declarations and entryComponents don’t forget to add the import.
3) Link from another existing page, don’t forget to include the import here as well.
Manual way
0) Create a folder (if needed)
1) Create a file <custom_page>.ts
import { Component } from '@angular/core';
@Component({
selector: 'page-custom',
templateUrl: 'custom.html';
})
export class CustomPage {
}
2) Create a <custom>.html
<ion-header>
<ion-navbar>
<ion-title>My title</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
</ion-content>
2) Modify app.module.ts and add your page to declarations and entryComponents don’t forget to add the import.
4) Link from another existing page, don’t forget to include the import here as well.
jueves, 24 de agosto de 2017
ionic: Start
0) Download node
1) npm install ionic cordova -g (-g install globally)
3) Create project
ionic start <project_name> (blank)
blank if you want no template
4) cordova platform add ios
5) cordova platform add android
6) cordova build
7) Open project on browser, keeps track of changes and rebuilds / re starts the app
ionic serve
8) Add platform
codova platform add ios (or android)
1) npm install ionic cordova -g (-g install globally)
3) Create project
ionic start <project_name> (blank)
blank if you want no template
miércoles, 12 de julio de 2017
iOS: Unit testing
1) Make sure your podfile looks like this:
2) Your test files should include:
3) Configuration:
platform :ios, '10.0'
use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
def common_pods
// your pods here
end
target 'MyApp' do
common_pods
end
target 'MyApp Tests' do
common_pods
end
2) Your test files should include:
import XCTest
@testable import MyApp
3) Configuration:
viernes, 7 de julio de 2017
iOS: Google maps markers
Google maps marker view's icon view is placed as shown on the image
That is, the icon view's bottom center is placed in the (lat, lng) provided. All the drawing has to be done inside the icon view, the marker will ignore the value of "clipToBounds" and will always take it as if it were true.
You can change the "groundAnchor":
The ground anchor specifies the point in the icon image that is anchored to the marker's position on the Earth's surface.
This point is specified within the continuous space [0.0, 1.0] x [0.0, 1.0], where (0,0) is the top-left corner of the image, and (1,1) is the bottom-right corner.
If the image has non-zero alignmentRectInsets, the top-left and bottom-right mentioned above refer to the inset section of the image.
jueves, 8 de junio de 2017
iOS: Select picture from camera or library
MyViewController
class MyViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
...
@IBOutlet weak var pictureImage: UIImageView!
let picker = UIImagePickerController()
...
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
...
}
...
// MARK: - Actions @IBAction func changePictureAction(_ sender: Any) {
...
changePhoto()
}
...
func changePhoto() {
let optionMenu = UIAlertController(title: nil, message: "Lets get a picture", preferredStyle: .actionSheet)
let selectFromLibraryAction = UIAlertAction(title: "Select photo from library", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
self.selectPictureFromLibrary()
})
optionMenu.addAction(selectFromLibraryAction)
if (UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)) {
let takePictureAction = UIAlertAction(title: "Take a picture", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
self.selectPictureFromCamera()
})
optionMenu.addAction(takePictureAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {
(alert: UIAlertAction!) -> Void in
print("Cancelled")
})
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
func selectPictureFromLibrary() {
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)
}
func selectPictureFromCamera() {
picker.sourceType = .camera
present(picker, animated: true, completion: nil)
}
...
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
pictureImage.contentMode = .scaleAspectFit
pictureImage.image = chosenImage
dismiss(animated:true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
Info.plist
Key: Privacy - Photo Library Usage Description
Type: String
Value: <you message>
Key: Privacy - Camera Usage Description
Type: String
Value: <you message>
class MyViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
...
@IBOutlet weak var pictureImage: UIImageView!
let picker = UIImagePickerController()
...
override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
...
}
...
// MARK: - Actions @IBAction func changePictureAction(_ sender: Any) {
...
changePhoto()
}
...
func changePhoto() {
let optionMenu = UIAlertController(title: nil, message: "Lets get a picture", preferredStyle: .actionSheet)
let selectFromLibraryAction = UIAlertAction(title: "Select photo from library", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
self.selectPictureFromLibrary()
})
optionMenu.addAction(selectFromLibraryAction)
if (UIImagePickerController .isSourceTypeAvailable(UIImagePickerControllerSourceType.camera)) {
let takePictureAction = UIAlertAction(title: "Take a picture", style: .default, handler: {
(alert: UIAlertAction!) -> Void in
self.selectPictureFromCamera()
})
optionMenu.addAction(takePictureAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: {
(alert: UIAlertAction!) -> Void in
print("Cancelled")
})
optionMenu.addAction(cancelAction)
self.present(optionMenu, animated: true, completion: nil)
}
func selectPictureFromLibrary() {
picker.sourceType = .photoLibrary
present(picker, animated: true, completion: nil)
}
func selectPictureFromCamera() {
picker.sourceType = .camera
present(picker, animated: true, completion: nil)
}
...
// MARK: - UIImagePickerControllerDelegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
pictureImage.contentMode = .scaleAspectFit
pictureImage.image = chosenImage
dismiss(animated:true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
}
Info.plist
Key: Privacy - Photo Library Usage Description
Type: String
Value: <you message>
Key: Privacy - Camera Usage Description
Type: String
Value: <you message>
iOS: WKWebKit not persisting cookies (login in not persisting when navigation out and into the web view)
I was having an issue that when loging in to a page through a WKWebKit the session didn't stick. Everytime I arrived at the page I was prompted to login.
We have to do the following.
We need to create a unique process pool to be shared among all WKWebKits and pass it along as a parameter to all of them (this wasn't necessary on UIWebView the way Apple handles the coookies changed):
var processPool: WKProcessPool?
somewhere where we create the WebViewController we pass said pool:
let webViewController = WebViewController()
webViewController.url = "some-url"
webViewController.processPool = processPool
then the web view controller that contains the WKWebKit we configure it like so:
class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var url: URL?
var webView: WKWebView!
var processPool: WKProcessPool?
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
if let pool = processPool {
webConfiguration.processPool = pool
}
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView
}
...
}
We have to do the following.
We need to create a unique process pool to be shared among all WKWebKits and pass it along as a parameter to all of them (this wasn't necessary on UIWebView the way Apple handles the coookies changed):
var processPool: WKProcessPool?
somewhere where we create the WebViewController we pass said pool:
let webViewController = WebViewController()
webViewController.url = "some-url"
webViewController.processPool = processPool
then the web view controller that contains the WKWebKit we configure it like so:
class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var url: URL?
var webView: WKWebView!
var processPool: WKProcessPool?
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
if let pool = processPool {
webConfiguration.processPool = pool
}
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
webView.navigationDelegate = self
view = webView
}
...
}
lunes, 5 de junio de 2017
iOS: Tableview row with dynamic size (adjusting to content)
tableView.estimatedRowHeight = 116
tableView.rowHeight = UITableViewAutomaticDimension
tableView.rowHeight = UITableViewAutomaticDimension
miércoles, 26 de abril de 2017
jueves, 20 de abril de 2017
jueves, 6 de abril de 2017
iOS: Search view
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating {
@IBOutlet var tableView: UITableView! // Add in interface builder
var items = [Item]()
var filteredItems = [Item]()
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
...
self.searchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.hidesNavigationBarDuringPresentation = false
controller.searchBar.sizeToFit()
// controller.searchBar.barStyle = UIBarStyle.black
controller.searchBar.barTintColor = settings.get(settingNamed: SettingCollection.General.PrimaryButtonBackgroundColor)?.colorValue
controller.searchBar.backgroundColor = settings.get(settingNamed: SettingCollection.General.PrimaryButtonBackgroundColor)?.colorValue
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
}
...
// MARK: - UITableViewDelegate & UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = filteredItems[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCell
// Populate cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = UIEdgeInsets.zero
}
if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
if cell.responds(to: #selector(setter: UIView.layoutMargins)) {
cell.layoutMargins = UIEdgeInsets.zero
}
}
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
if searchText.isEmpty {
filteredItems = items
tableView.reloadData()
return
}
filteredItems = items.filter { item in
return item.text.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()
}
}
@IBOutlet var tableView: UITableView! // Add in interface builder
var items = [Item]()
var filteredItems = [Item]()
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
...
self.searchController = ({
let controller = UISearchController(searchResultsController: nil)
controller.searchResultsUpdater = self
controller.dimsBackgroundDuringPresentation = false
controller.hidesNavigationBarDuringPresentation = false
controller.searchBar.sizeToFit()
// controller.searchBar.barStyle = UIBarStyle.black
controller.searchBar.barTintColor = settings.get(settingNamed: SettingCollection.General.PrimaryButtonBackgroundColor)?.colorValue
controller.searchBar.backgroundColor = settings.get(settingNamed: SettingCollection.General.PrimaryButtonBackgroundColor)?.colorValue
self.tableView.tableHeaderView = controller.searchBar
return controller
})()
}
...
// MARK: - UITableViewDelegate & UITableViewDataSource
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredItems.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item = filteredItems[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! MyCell
// Populate cell
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if cell.responds(to: #selector(setter: UITableViewCell.separatorInset)) {
cell.separatorInset = UIEdgeInsets.zero
}
if cell.responds(to: #selector(setter: UIView.preservesSuperviewLayoutMargins)) {
cell.preservesSuperviewLayoutMargins = false
}
if cell.responds(to: #selector(setter: UIView.layoutMargins)) {
cell.layoutMargins = UIEdgeInsets.zero
}
}
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchText: searchController.searchBar.text!)
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
if searchText.isEmpty {
filteredItems = items
tableView.reloadData()
return
}
filteredItems = items.filter { item in
return item.text.lowercased().contains(searchText.lowercased())
}
tableView.reloadData()
}
}
Suscribirse a:
Entradas (Atom)


