• Skip to primary navigation
  • Skip to main content

Ravi Shankar

Lifelong Learner

  • About
  • Portfolio

Save messages in sent items folder in Outlook

By Ravi Shankar 7 Comments

Microsoft Outlook automatically saves the sent messages in sent items folder. But if you do not want to automatically save the sent messages then you can turn off this feature using Outlook Options. Listed below are steps to enable or disable saving copies of messages in Sent Items folder in Outlook 2013, Outlook 2010 and Outlook 2007.

Outlook 2013 and Outlook 2010

Click the File menu –> click the Options link . In the Options window select the Mail tab and scroll down to Save Messages section.

Save copies of messages in the Sent Items folder in Outlook 2013

You can turn off or disable the save sent messages sent items folder by un marking the checkbox with label as Save copies of messages in the Sent Items folder.

Save message in Sent Items for single message in Outlook 2013 and Outlook 2010

The above settings would affect all the message but if you want to specify only for selected messages then you can use the options available as part of Message window.

In the message window, navigate to Options menu then to the more options section.

Save Sent Item to Outlook 2010

Click the down arrow available below the Save Sent Item To menu option.

Do Not save message Outlook 2013

The different options that are available are

Use Default Folder – This would save the sent messages in the default sent items folder.

Other Folder – This allows users to specify the folder where this messages needs to be saved.

Select Folder Outlook 2010

Do Not Save – This will not save the sent messages to any folder.

Outlook 2007

In Outlook 2007 to enable or disable “Save copies of messages in Sent Item folder”, Click Tools ->Options  -> Email Options

Save messages in Sent Items folder in Outlook 2007

Under Message Handling section, by checking Save copies of messages in Sent Items folder, messages that are being sent would be saved to Sent Items folder.

Also See: How to automatically save messages in Outlook 2010

Search photos on Flickr – Web Service

By Ravi Shankar 1 Comment

In this tutorial we will see the steps required to write a demo app that retrieves photos from Flickr based on search text and display them in a UICollectionView. This also covers how to integrate 3rd party libaries using CocoaPods.

Flickr API

Register your app in Flickr and get the API key details. You will need the API key to access the Flickr Photo Search API.

Project Setup

Create a new project by selecting Single View Application template and selecting language as Swift.

Install 3rd Party Libraries

We will be using CocoaPods to install third party libraries. First make sure to install CocoaPods on your Mac. Launch terminal window, navigate to the newly created project folder and create a file with name as Podfile. Edit the Podfile and add the following content

use_frameworks!
pod ‘Alamofire’
pod ‘SwiftyJSON’
pod ‘Haneke’

Alamorfire, SwiftyJSON and Haneke are the thirdparty libraries that will be used in this project. Alamofire for WebSerice call, SwiftJSON for parsing JSON data and Haneke for caching images.

After adiding the required libraries, type pod install on the terminal window. This should install the required libraries and create the necessary workspace. Now open <Project Name>.xcworkspace to add the functionality to the project.

Model Class

Add a new file (Photo.swift) to act as a place holder for storing photo details. Photo struct has properties for id, title, farm, secret, server and computed property which constructs the URL of the photo.

[code language=”swift”]
import UIKit

struct Photo {
var id: String
var title: String
var farm: String
var secret: String
var server: String
var imageURL: NSURL {
get {
let url = NSURL(string: "http://farm\(farm).staticflickr.com/\(server)/\(id)_\(secret)_m.jpg")!
return url
}
}
}
[/code]

 

Web Service Integration

Add new Swift file to the project and provide a name as Services.swift. Add the following code snippet to Services.swift

[code language=”swift”]import Alamofire
import SwiftyJSON

protocol FlickrPhotoDownloadDelegate {
func finishedDownloading(photos:[Photo])
}

class Services {

let API_KEY = “"
let URL = "https://api.flickr.com/services/rest/"
let METHOD = "flickr.photos.search"
let FORMAT_TYPE:String = "json"
let JSON_CALLBACK:Int = 1
let PRIVACY_FILTER:Int = 1

var delegate:FlickrPhotoDownloadDelegate?

// MARK:- Service Call

func makeServiceCall(searchText: String) {

Alamofire.request(.GET, URL, parameters: ["method": METHOD, "api_key": API_KEY, "tags":searchText,"privacy_filter":PRIVACY_FILTER, "format":FORMAT_TYPE, "nojsoncallback": JSON_CALLBACK])
.responseJSON { (request, response, data, error) in
if data != nil {
let jsonData:JSON = JSON(data!)
let photosDict = jsonData["photos"]
let photoArray = photosDict["photo"]
var photos = [Photo]()

for item in photoArray {
let id = item.1["id"].stringValue
let farm = item.1["farm"].stringValue
let server = item.1["server"].stringValue
let secret = item.1["secret"].stringValue
let title = item.1["title"].stringValue
let photo = Photo(id:id, title:title, farm:farm, secret: secret, server: server)
photos.append(photo)
}
self.delegate?.finishedDownloading(photos)
} else {
println(error)
}
}

}
}
[/code]

The above code does the following

  • Makes a web service call to the flickr photo search API using Alamofire third party library.
  • Web Service results are parsed using SwiftyJSON library. 
  • The delegates are notified about the completion of the download by pasisng the photos array.

Design User Intrerfaces

Navigate to Main.storyboard, add a UICollectionView and UISearchBar to the ViewController as shown in the below screenshot.

Make sure add Auto Layout constriants so that the UI looks good for both iPad and iPhone. If you need help with Auto Layout then check out this tutorial.

As shown in the above screenshot, you need to add UIImageView to the CollectionViewCell. Now embed this ViewController inside Navigation Controller using the Editor -> Embed In -> Navigation Controller menu option.

Add another second View Controller to the Storyboard which would act as the Detail View Controller for displaying selected Photo.

Add Custom Cell

Create a new file (PhotoCell.swift) by selecting CocoaTouch class and keeping the base class as UICollectionViewCell. Set this class as the Custom Class for UICollectionViewCell in the Interface builder. Then create IBOutlet for the imageView in PhotoCell.

[code language=”swift”]
import UIKit

class PhotoCell: UICollectionViewCell {

@IBOutlet weak var imageView: UIImageView!

}
[/code]

 

Add PhotosViewController

 

You can rename the existing ViewController.swift to PhotosViewController.swift file. In the storyboard, select the ViewController with CollectionView and set the custom class name to PhotosViewController.

Create IBOutlets for UISearchBar and UICollectionView in PhotosViewController.

[code language=”swift”]@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var collectionView: UICollectionView!
[/code]

Implement the SearchBar delegate method and service call for searching photos based on the entered Search Text.

[code language=”swift”]// MARK:- SearchButton

func searchBarSearchButtonClicked(searchBar: UISearchBar) {
searchForPhotos()
searchBar .resignFirstResponder()
}

// MARK:- SearchPhotos

func searchForPhotos() {
service.makeServiceCall(searchBar.text)
}
[/code]

Also add the following code snippet that processes the downloaded photos returned from the web service call. All UI calls needs to be done in the main thread hence setting the photos instance variable and update CollectionView are done within dispatch_async(dispatch_get_main_queue()).

[code language=”swift”]// MARK:- Flickr Photo Download
func finishedDownloading(photos: [Photo]) {
dispatch_async(dispatch_get_main_queue(), { () -&gt; Void in
self.photos = photos
self.collectionView?.reloadData()
})
}[/code]

Set the all the delegates and default value for the search bar in viewDidLoad method.

[code language=”swift”]override func viewDidLoad() {
super.viewDidLoad()

collectionView.dataSource = self
searchBar.delegate = self
collectionView.delegate = self
service.delegate = self

// default
searchBar.text = "famous quotes"
searchForPhotos()
}[/code]

Add CollectionViewDataSource methods

In the PhotosViewController add the CollecitonViewDataSource methods for displaying the photos. This can be done by adding an extension to the PhotosViewController class.

[code language=”swift”]extension PhotosViewController: UICollectionViewDataSource {
// MARK:- UICollectionViewDataSource methods

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int {
return 1
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return photos.count
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
var cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! PhotoCell
let photo = photos[indexPath.row]
cell.imageView.frame.size = cell.frame.size
cell.imageView.hnk_setImageFromURL(photo.imageURL)
return cell
}

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
let photo:Photo? = photos[indexPath.row]
if let photo = photo {
let detailViewController = storyboard?.instantiateViewControllerWithIdentifier("DetailViewController") as! DetailViewController
detailViewController.photo = photo
presentViewController(detailViewController, animated: true, completion: nil)
}
}
}[/code]

The cellForItemAtIndexPath uses the custom cell (PhotoCell) for displaying the Photo. Also uses the thirdparty library Haneke to load the imageView. And in the didSelectItemAtIndexPath method add the code for calling the DetailViewController by passwing the selecting photo.

Finally in the PhotosViewController add the code that calcuates the Cell Size to be displayed on the CollecitonView. This is done by implementing the UICollectionViewDelegateFlowLayout method.

[code language=”swift”]extension PhotosViewController: UICollectionViewDelegateFlowLayout {
// MARK:- UICollectioViewDelegateFlowLayout methods

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -&gt; CGSize
{
let length = (UIScreen.mainScreen().bounds.width-15)/4
return CGSizeMake(length,length);
}
}
[/code]

Check out this article in stackoverflow for calculating the size of the CollectionViewCell.

Add DetailViewController

Add a new CocoaTouch class of Subclass as UIViewController with name as DetailViewController. Then add the following code to the class file.

[code language=”swift”]
import UIKit
import Haneke

class DetailViewController: UIViewController {

var photo:Photo?
var imageView:UIImageView?

override func viewDidLoad() {
super.viewDidLoad()

if let photo = photo {

imageView = UIImageView(frame: CGRectMake(0, 0, 320, 320))
imageView?.hnk_setImageFromURL(photo.imageURL)
view.addSubview(imageView!)

let tapGestureRecogonizer = UITapGestureRecognizer(target: self, action: Selector("close"))
view.addGestureRecognizer(tapGestureRecogonizer)
}
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}

// MARK:- viewDidLayoutSubviews

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

let size = view.bounds.size
let imageSize = CGSizeMake(size.width,size.width)
imageView?.frame = CGRectMake(0.0, (size.height – imageSize.height)/2.0, imageSize.width, imageSize.height)

}
// MARK:- close
func close() {
dismissViewControllerAnimated(true, completion: nil)
}
}[/code]

The above code does the following

  • Calculates the size of the imageview and aligns it to the centre of the ViewController.
  • Loads the image using the third party library Haneke.
  • Adds a gesture recogonizer that dismisses the ViewContorller on tap gesture.

Dowload the source code from here.

How to change default Auto Recover file location in Word

By Ravi Shankar 1 Comment

Microsoft has an auto recover feature using which a word document can be retrieved after an unplanned disruptions, such as a power outage or a crash. The word document gets saved to a default location during such as disruptions. If you want to change the default Auto Recover file location then you can use Word Advanced Options. Listed below procedure to change the default auto recover location in Word 2007, Word 2010 and Word 2013.

Change auto recover file location in Word 2013 and Word 2010

To the change the default Auto Recover file location in Word 2010 and Word 2013, click the File menu –> Options link. And then navigate to the Save tab. Under the Save documents, there is option for for specifying the Auto recover file location. This can be done by typing the required folder location in the text field available next to the label Auto Recover file location. You can also use the Browse button to locate the required folder. After the specifying the folder, click OK to apply the changes to the file location.

AutoRecover file location in Word 2013 and Word 2010

Auto Recover file location in Word 2007

The settings in Word 2007 can be accessed through Word Options -> Save menu

AutoRecover file location in Word 2007

Under Save documents section, navigate to AutoRecover file location and specify the new location.

Also See: How to recover saved WiFi password on WIndows 7

Reset slide settings in PowerPoint 2013 & 2010

By Ravi Shankar 1 Comment

PowerPoint 2013 and 2010 have a reset option that can be used for resetting the position, size and formatting of slide place holders to the default settings. For example if you have resized the place holders for adding title and subtitle and now want to revert to default settings then you can use this reset option.

image

The reset option can be accessed via the home menu. In PowerPoint 2010 home menu, navigate to the slides section. And click Reset menu option, to revert the changes done to the slide to the default position.

image

UICollectionView Demo in Swift

By Ravi Shankar

UICollectionView can be used for displaying set of data in rows and columns The main difference between UICollectionView and UITableView is that CollectionView can be display more than one column. The following topics are covered in this article

  • Simple collection view demo
  • Displaying data in Collection View
  • Implementiing Custom Cell 
  • Adding Section Headers
  • Highlighting Cell
  • Insert Cell
  • Delete Cells

Project Setup

Create a new project by selecting Single View Application template.

Provide the necessary details in the Project options screen and select the language as Swift.

Adding CollectionView

Let us first try out simple collection view to get a better understanding of how various components works. Then let us move on to a demo that displays various fruits grouped in different section. And you will be able insert and delete cells from the Collection View.

Navigate to Main.storyboard, disable Auto Layout and size classes using File Inspector option.

Then drag and drop CollectionView from object library to ViewController. The ViewController with CollectionView should look as shown below.

The square box inside collection view is UICollectionViewCell. Using Attributes Inspector, change the background colour of CollectionView to white. Then select UICollecitonViewCell and enter value for identifier as “CellIdentifier”

Using Assistant Editor, add an IBOutlet to CollectionView in ViewController.swlft file.

[code language=”swift”]@IBOutlet weak var collectionView: UICollectionView![/code]

Implement UICollectionViewDataSource methods

When the CollectionView loads, we need to specify the data for the cells. This can be done by implementing
UICollectionViewDataSource related methods. UICollectionViewDataSource protocols defines the following mandatory and optional methods.

[code language=”swift”]protocol UICollectionViewDataSource : NSObjectProtocol {

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell

optional func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int

// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:
optional func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -&gt; UICollectionReusableView
}[/code]

First make sure to set the delegate property of collectionView to self in viewDidLoad function. Then add instance level property for storing Cell Identifier.

[code language=”swift”]let identifier = "CellIdentifier"

override func viewDidLoad() {
super.viewDidLoad()

collectionView.dataSource = self
}[/code]

Now add the implementation for mandatory methods numberOfItemsInSection and cellForItemAtIndexOath in ViewController.swlft. We can do this by adding an extension to ViewController class. Add this extension after the closing parenthesis of View Controller class.

[code language=”swift”]// MARK:- UICollectionViewDataSource Delegate
extension ViewController: UICollectionViewDataSource {

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return 12
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier, forIndexPath: indexPath) as! UICollectionViewCell
cell.backgroundColor = UIColor.redColor()

return cell
}
}
[/code]

We have temporarily hard coded the number of items to be shown as 12. Using dequeReusableCellWithReuseIdentifier funciton, create cells based on index path. Then change the background color of cell to red. Now when you build and run the project, you should see collection view showing some cells as shown below.

If you want to have 3 rows and 4 columns then use the Collection View’s Size Inspector to make the appropriate changes to Cell Size and Minimum Spacing attributes.

If you Build and Run the project you should notice the changes.

Collection View DataSource

Now for the actual demo project, let us create a seperate class which will act as DataSource. Before creating a datasource, let us create a model class with file name as Fruit.swift. The implementation of the Fruit class should look as shown below

[code language=”swift”]class Fruit {
var name:String?
var group:String?

init(name: String, group: String) {
self.name = name
self.group = group
}
}
[/code]

 

Fruit struct is just a place holder for storing fruit related information. Now create another class for DataSource and name it as DataSource.swift. This class will provide the data related methods to the CollectionView. Durining the initialisation of the class, the data is read from plist and populated to fruits and groups array. Then using the respective helper methods the details will be retrieved by CollectionView.

[code language=”swift”]import Foundation

class DataSource {

init() {
populateData()
}

var fruits:[Fruit] = []
var groups:[String] = []

func numbeOfRowsInEachGroup(index: Int) -&gt; Int {
return fruitsInGroup(index).count
}

func numberOfGroups() -&gt; Int {
return groups.count
}

func gettGroupLabelAtIndex(index: Int) -&gt; String {
return groups[index]
}

// MARK:- Populate Data from plist

func populateData() {
if let path = NSBundle.mainBundle().pathForResource("fruits", ofType: "plist") {
if let dictArray = NSArray(contentsOfFile: path) {
for item in dictArray {
if let dict = item as? NSDictionary {
let name = dict["name"] as! String
let group = dict["group"] as! String

let fruit = Fruit(name: name, group: group)
if !contains(groups, group){
groups.append(group)
}
fruits.append(fruit)
}
}
}
}
}

// MARK:- FruitsForEachGroup

func fruitsInGroup(index: Int) -&gt; [Fruit] {
let item = groups[index]
let filteredFruits = fruits.filter { (fruit: Fruit) -&gt; Bool in
return fruit.group == item
}
return filteredFruits
}
}[/code]

Then add the required images to Images.xcassets, you can download the images for this project from GitHub.

Also add/create a new plist file which contains the information about the fruits and the group they belong to (download it from here).

Add Custom CollectionViewCell

For displaying image and caption in Collection View Cell, create a Custom Cell subclass of UICollectionViewCell. Provide name for the new file as Fruit Cell.

Navigate to Main.storyboard, select CollectionViewCell and using identity inspector set the class as FruitCell.

Drag and drop UIImageView and Label on to CollectionViewCell and add corresponding IBOutlets to FruitCell class.

[code language=”swift”]
import UIKit

class FruitCell: UICollectionViewCell {

@IBOutlet weak var caption: UILabel!
@IBOutlet weak var imageView: UIImageView!
}
[/code]

Display Data

We need to make changes to the ViewController extension for displaying the data form the DataSource with CustomCell. First Create an instance variable for DataSource in ViewController class

[code language=”swift”]let dataSource = DataSource()
[/code]

Then make the following changes to UICollectionViewDataSource extension to reflect the DataSource and FruitCell classes.

[code language=”swift”]
extension ViewController : UICollectionViewDataSource {

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -&gt; Int {
return dataSource.groups.count
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -&gt; Int {
return dataSource.numbeOfRowsInEachGroup(section)
}

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -&gt; UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(identifier,forIndexPath:indexPath) as! FruitCell

let fruits: [Fruit] = dataSource.fruitsInGroup(indexPath.section)
let fruit = fruits[indexPath.row]

let name = fruit.name!

cell.imageView.image = UIImage(named: name.lowercaseString)
cell.caption.text = name.capitalizedString

return cell
}
}[/code]

Now if you build and run the project, you should see the colleciton view displaying fruits along with the caption.

The rows and columns are not properly aligned, we can fix this calculate the size of the cell based on height and width of collection view. Let us make the Collection View to display 2 cells per row. Navigate to Main,storyboard, update the Cell Size property to 182 as shown below.

Make sure to adjust the UIImageView and Label to fit the changed Collection View cell size. Now if you compile and run the project, the simulator should look as shown below.

Add Section Header

Headers for each can be added by implementing the viewForSupplementaryElementOfKind method defined as part of UICollectionViewDataSource protocol. We already have function in DataSource class that returns caption for each section. Let us add new Custom class for CollectionView section header and map this class to the header view in Interface builder.

Create FruitsHeaderView with subclass as UICollectionResuableView. Then navigate to Main.storyboard, select Collection View -> Attributes Inspector and enable Section Header under Accessories.

Now select the Section Header in the Collection View and set the class as FruitsHeaderView using Identity Inspector. In the Attributes Inspector enter the Identifier as HeaderView

Add UILabel to the header view to display the seciton title and corresponding IBOutlet to FruitsHeaderView class. You can also provide some background colour for the HeaderView,

[code language=”swift”]
import UIKit

class FruitsHeaderView: UICollectionReusableView {
@IBOutlet weak var sectionLabel: UILabel!
}
[/code]

Now add the following viewForSupplementaryElementOfKind implementation to the UICollectionViewDataSource extension in ViewController class.

[code language=”swift”] func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -&gt; UICollectionReusableView {

let headerView: FruitsHeaderView = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: headerViewIdentifier, forIndexPath: indexPath) as! FruitsHeaderView

headerView.sectionLabel.text = dataSource.gettGroupLabelAtIndex(indexPath.section)
return headerView
}
[/code]

 

Make sure to add an instance variable let headerViewIdentifier = “HeaderView” in ViewController.class. In viewForSupplementaryElementOfKind function, we are creating an instance of FruitsHeaderView class using dequeueReusableSupplementaryViewOfKind function. Then set the section label by retrieving the caption from DataSource class. Build and run the app on iPhone simulator should show the following

Add Detail View

Now to add a detail View, let us first embed the ViewController in Navigation Controller. Then add another ViewController for using it as Detail View. Create a segue by Control + drag from CollectionView Cell to the new View Controller and select the Segue as Push.

Add UIImageView to the DetailViewController and centre align it to the View. Then add a new class (sub class of UIViewController) and name the file as DetailViewController

Map this class to the Second View Controller in the Interface builder. Then add the IBOutlet for the UIImageView in DetailViewController class.

@IBOutlet weak var imageView: UIImageView!

From the main View Controller, the selected Fruit needs to be passed to the DetailViewController class. Add a new property which is of type Fruit

[code language=”swift”]var fruit: Fruit?[/code]

In viewDidLoad method, add code to populate the title and image.

[code language=”swift”]if let fruit = fruit {
navigationItem.title = fruit.name?.capitalizedString
imageView.image = UIImage(named: fruit.name!.lowercaseString)
}[/code]

Navigate to ViewController.class and implement the prepareForSegue and getIndexPathForSelectedCell function.

[code language=”swift”]// MARK:- prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// retrieve selected cell &amp; fruit
if let indexPath = getIndexPathForSelectedCell() {

let fruit = dataSource.fruitsInGroup(indexPath.section)[indexPath.row]

let detailViewController = segue.destinationViewController as! DetailViewController
detailViewController.fruit = fruit
}
}

func getIndexPathForSelectedCell() -&gt; NSIndexPath? {

var indexPath:NSIndexPath?

if collectionView.indexPathsForSelectedItems().count &gt; 0 {
indexPath = collectionView.indexPathsForSelectedItems()[0] as? NSIndexPath
}
return indexPath
}
[/code]

In the above function using the selected Item indexPath the corresponding fruit is retrieved from DataSource class. Then this information is passed to the DetailViewController.

Highlight Selection

When the user taps any cell, it would nice to see the cell getting highlighted. This can be done by implementing following function as extension.

[code language=”swift”]// MARK:- UICollectionViewDelegate Methods

extension ViewController : UICollectionViewDelegate {
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
highlightCell(indexPath, flag: true)
}
}

func collectionView(collectionView: UICollectionView, didDeselectItemAtIndexPath indexPath: NSIndexPath) {
highlightCell(indexPath, flag: false)
}
}[/code]

Also make sure to add the collectionView.delegate = self to viewDidLoad function. Then add the following highlight function inside ViewController class.

[code language=”swift”]// MARK:- Highlight
func highlightCell(indexPath : NSIndexPath, flag: Bool) {

let cell = collectionView.cellForItemAtIndexPath(indexPath)

if flag {
cell?.contentView.backgroundColor = UIColor.magentaColor()
} else {
cell?.contentView.backgroundColor = nil
}
}
[/code]

 

Since we want to dehighlight the cell when the user returns from the DetailViewController. implement the viewDidAppear function with de-hightlight functionality.

[code language=”swift”]override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)

if let indexPath = getIndexPathForSelectedCell() {
highlightCell(indexPath, flag: false)
}
}
[/code]

Insert Cell

CollectionView provides insertItemsAtIndexPath method for adding new cell to CollectionView. Navigate to Main.storyboard, add new BarButtonItem to ViewController and set the Identifier as Add.

Add an IBAction to ViewController class and map it to the Add button. In the DataSource class add the following function which inserts new item to fruit model and returns the index.

[code language=”swift”]
// MARK:- Add Dummy Data
func addAndGetIndexForNewItem() -&gt; Int {

let fruit = Fruit(name: "SugarApple", group: "Morning")

let count = fruitsInGroup(0).count
let index = count &gt; 0 ? count – 1 : count
fruits.insert(fruit, atIndex: index)

return index
}
[/code]

Then modify the addNewItem IBAction method with the following piece of code.

[code language=”swift”] // MARK:- Add Cell
@IBAction func addNewItem(sender: AnyObject) {
let index = dataSource.addAndGetIndexForNewItem()
let indexPath = NSIndexPath(forItem: index, inSection: 0)
collectionView.insertItemsAtIndexPaths([indexPath])
}
[/code]

Delete Cell

Add Edit button to the navigation bar to allow users to perform delete operation. This can be done by adding the following line in viewDidLoad method.

[code language=”plain”]navigationItem.leftBarButtonItem = editButtonItem()[/code]

Then add a toolbar with button to delete the selected cell. Navigate to Main.storyboard, drag and drop toolbar on to View Controller. Add a BarButtonItem to the toolbar and select the identifier as Trash.

This toolbar should be displayed when the user taps on Edit button. Create an IBOutlet for the toolbar and add the following line to the viewDidLoad method.

[code language=”swift”]toolBar.hidden = true[/code]

Implement the setEditing function to enable or disable editing operation. In the below function, when editing is enabled, users will be allowed to select and delete multiple cells. The toolbar will be displayed or hidden based on editing flag.

[code language=”swift”]
// MARK:- Editing
override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
collectionView?.allowsMultipleSelection = editing
toolBar.hidden = !editing
}
[/code]

Now hook up Trash button in the Interface builder to IBAction for performing the delete operation. Add the following code snippet to deleteCells IBAction method. This first retrieves the indexpath for all the selected items. Then iterates through the indexpaths and to get the list of fruits to be deleted from model.

[code language=”swift”]
@IBAction func deleteCells(sender: AnyObject) {

var deletedFruits:[Fruit] = []

let indexpaths = collectionView?.indexPathsForSelectedItems()

if let indexpaths = indexpaths {

for item in indexpaths {
let cell = collectionView!.cellForItemAtIndexPath(item as! NSIndexPath)

collectionView?.deselectItemAtIndexPath(item as? NSIndexPath, animated: true)
// fruits for section
let sectionfruits = dataSource.fruitsInGroup(item.section)
deletedFruits.append(sectionfruits[item.row])
}

dataSource.deleteItems(deletedFruits)

collectionView?.deleteItemsAtIndexPaths(indexpaths)
}
}
[/code]

 

And in the DataSource class, add a function to delete fruits from the model. Also add an extension to array to get the index of the object based on the selected item (This will not be needed in Swift 2.0).

[code language=”swift”]
// MARK:- Delete Items
func deleteItems(items: [Fruit]) {

for item in items {
// remove item
let index = fruits.indexOfObject(item)
if index != -1 {
fruits.removeAtIndex(index)
}
}
}
[/code]

We need to cancel the segue operation when the edit operation is enabled, you can do this by implementing the following method in ViewController class.

[code language=”swift”]
// MARK:- Should Perform Segue
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -&gt; Bool {
return !editing
}[/code]

Download the source code from here

Adaptive Layout in iOS

By Ravi Shankar

Adaptive Layout was introduced in iOS 8 to address the problem of designing user interface for different devices and screen sizes. In the earlier version of iOS, we had to maintain different storyboards for iPad and iPhone and with Adaptive Layout we just need one storyboard for all the devices. Some of the main components of Adpative Layout are Auto Layout, Size Classes and Trait Collections. Let us try to understand Adpative Layout by designing the following User Interface for various devices and screen sizes.

Create an universal project choosing Single View Application template. You can download the project from GitHub to get the images used in this demo and add them to Images.xcassets.

iPhone (Portrait)

Make sure you have selected the size classes as wAny hAny in the Storyboard.

Add a UIImageView, button and 2 labels then provide necessary details as shown below.

First let us design the screen for iPhones in Portrait mode by keeping Preview (Assistant Editor) adjacent to Interface builder.

Select the iPhone 6 caption label, align it centre horizontally to the container by using the Align option.

Set the distance from top layout to the label as 5 using the Pin option.

Now select the imageview and align it centre horizontally and Vertically to the container by using the Align option.

The specify the width and height constraint for the imageview using the Pin option. This would ensure that the size of imageview is uniform in all the devices.

Now select the Buy Now button and add contraints to the trailing and bottom of the button. Control + drag from button to View and select Trailing space to container margin.

Repeat Control + drag from button to the bottom of the View and select Bottom Space to Bottom Layout Guide.

Then using the Pin option add width and height constraints for the button.

Finally the select the label which is used for displaying the price and Control + drag from label to the container.

Edit the Trailing Space constraint for Price label with Buy Now button and set it to 5.

Previewing the screen changes for iPhone 3.5 and iPhone 4 should look as shown below

iPad (Portrait & Landscape)

iPad has lots of screen space compared to an iPhone. Let us to see how to maximize the screen usage of an iPad by adding an extra image.

Set the size classes to wRegular hRegular to design user interfaces for iPad and iPhone. The imageview is currently aligned to centre both horizontally and vertically. We need to remove the horizontal constraint (Center X) so that the imageview can be moved towards the left handside. This should create an extra space to add another imageview to the View Controller.

Disable the Center X constraint for iPhone by navigating to Size Inspector and press the delete key.

Then pin the imageview to left side of the view without setting any margin (Pin option).

Use the Update Frame option under Resolve Auto Layout Issues to move the views based on the applied constraints. Add another ImageView to View Controller then select an iPhone 6 black image and set the view mode to Aspect Fit.

Control + drag from the imageview on the right hand side to imageview on the left hand side. Select Center Y from the list of available constraints.

Changing Font Size for Size Classes

Adaptive Layout allows you to specify different font size based on the size class. In the Show Attributes Inspector, click the + sign next Font option and choose wRegularWidth hRegularHeight option. Now you can customize the font properties specific to iPad

Now you should see the extra image just for iPads in portrait and Landscape mode. Still there are lots of empty space but you can fill them as part of your code challenege :-). May be you can other details such as add description, rating button etc..

When you navigate back to wAny hAny size classes, the document outline should show the new image as greyed out. As the second imageview is available only in regular size classes. Also the attributes inspector for the second imageview should provide the details on installed size classes.

The above screenshot shows that the control installed only in wR wH size classes and not wAny hAny size classes.

iPhone (Landscape)

When previewing the design in both portrait and landscape, you must have noticed that some controls are hidden in landscape mode. This can be fixed by making necessary changes to compact size classes.

Set the size classes to wAny hCompact in the storyboard. Select the imageview, navigate to Size Inspector and disable the Center X constraint.

Adjust the size of imageview if it is too large in landscape mode. To reflect frame changes, select Update Constraint under Resolve Auto Layout Issues option. Another way is by editing the width and height constraint for the imageview.

Since we want to move the price lable above the Buy Now button, remove all the constraints associated with the label.

Move the label just above the Buy Now button and centre align to the imageview.

Control + drag from Price label to Buy Now button and select Center X constraint.

Repeat the above step but this time from Price label to ImageView and select Center Y Constraint.

The final preview of screen in iPhone 3.5 portrait and landscape mode should look as shown below.

Download the source code from here

Summary

We have covered some basics of Adaptive Layout by designing user interface with size classes. changing font attibutes, installing controls,disable and editing constraints based on different size classes.

Auto Layout in iOS

By Ravi Shankar 5 Comments

Using Auto Layout feature developers can align UI controls for different devices, screen sizes and orientation. This reduces the code to be maintained and makes life easy for the developers. Auto Layout solves UI design issues by creating relationship between the UI elements. This follows constraint based layout system where you can define contraints for each UI elements. Let us see some basics of Auto Layout by looking at four different scenarios

The objective of this article is to provide details on the following

  • Different ways to add constraints to UI elements.
  • How to centre align a control to both vertically and horizantally to container.
  • Arrange three controls in single column with centre aligned horizontally to the container.
  • Design simple login form by embeding the controls inside view
  • Design a form where the width of controls gets adjusted based on device orientation.
  • Clear and Edit constraints.
  • Pinning constraint and Updating frames

Center Align image Vertical and Horizontal to the container

For this demo, let us start with a single view application project. Drag and drop an UIImageView from object libary on to View Controller. Copy an image to your project and set that image to UIImageView using Attributes Inspector (Download the image from GitHub project).

You might be familiar with Size Inspector under Xcode’s Utilies Pane. This helps us to enter the height, width, x and y position for any UI elements.

Another alternate way to enter the size and postion for elements by adding constraints using the Auto Layout option which is available at the bottom of the Interface builder.

Select the Click the Pin option, enter value for Width and Height as 300 then Add these 2 Constraints.

After applying the constraint, you should notice orange dashed line indicating that your control is out of position. Let us update the frame afer applying all the required constraints.

Click Align option (first option) and select Horizontal and Vertical Center in Container then Add these 2 Constraints.

If the ImageView on the ViewController is in misplaced position, the document outline will show an yellow color indication mark at top right hand corner. You can select that icon to find more details about the issue.

Document Outline

Document Outline in the Storyboard lists down the installed controls for a scene. Also you can the list of constraints added for these controls. If you do not need any constraint then you select it and delete them in Document Outline.

The missplaced views can be fixed by selecting Update Frames option under Resolve Auto Layout Issues (Auto Layout option with a triangle).

Preview User Interface changes

Now you can preview user interface changes on various device by using the Preview option. Click the icon for showing Assistant Editor window. Navigate to Preview and select Main.storyboard option as shown in the below screenshot.

You can use + sign to preview the screen in a specific device and also use rotate screen option to preview the changes in different screen orientation.

Arrange three Buttons in single column

In the next demo, we wil try to arrange three buttons aligned horizontally center to View and in a single column. Add a View Controller to the storyboard then drag drop three buttons on the View Controller. Though we have used the guidelines to align these buttons they don’t look the same when you preview them.

Now let us see how to fix these UI issues by adding constraints.

First select the Button with caption as Auto Layout 2 and make it Horizontal and Vertical Center in Container then Add these two constraints. This would make sure the Auto Layout 2 button is aligned center to the View both vertically and horizontally.

Select the button with caption as Auto Layout 1. Use the Aign option and add Horizontal Center in Container constraint.

Now you need to specify the Centre X and Verical Spacing constraint for this button. This can be done by control dragging from Auto Layout 1 button to Auto Layout 2 and you will be presented with the following option.

Select Vertical Spacing to position the control at constant distance from Auto Layout 2. Repeat the same control drag from Auto Layout 1 and Auto Layout 2 and this time choose Centre X.

Now repeat the above steps for Auto Layout 3 with Auto Layout 2 i.e add Centre X and Vertical Spacing constraints.

 

Scenario 3:- Adjust control width based on screen orientation

This scenario explains how to add constraints so that controls width increases or decreases based on the screen size. For example in the below screenshots, the width for textfields provided for entering name and Age gets adjusted based on screen orientation

Add a new View Controller on to Storyboard then add 2 labels and 2 textfields and a button. Provide the caption for both labels as Name, Age and Submit (button) respectively. We need to add constraints to labels so that their width and position are fixed at the specified location. And for both the textfields, constraints have to be added to trailing edge so that width increases or decreases based on the orientation

Add three constraints to the label with caption as Name using the pin option as shown in the below screenshot.

Repeat the same for label with caption as Age

Select the textfield adjacent to Name label, control drag from textfield to the container then select Trailing Space to Container Margin.

Need to align the textfield with the label, control drag from text field to name label and select Centre Y from the list of constraints.

Keeping the textField selected, navigate to Size Inspector (Utilities Pane) and cick Edit on Trailing Space constraint. Set the value for the constant as 10 as we want to maintain the space between textfield and container to 10 in both landscape and portrait mode.

Repeat the above steps done for Age textfields as well.

Finally we need to add two constraints for the Submit button to make sure it is aligned on the right hand side at certain distance from the Top Layout. Control drag from button to top of the container and select Top Space to Top Layout Guide.

Again repeat the above step by this time to side of the container and select Trailing Space to Container Margin.

Now prevewing the screen in Portait and Landscape mode should look as shown below.

Scenario 4:- Apply constraints to Embedded View

In this demo, let us see how to embed controls within a view and apply constraints to the embedded View instead of applying to the individual constraints.

Note :- Button has been incorrect named as Password it needs to be Register. The source code has been updated with this name change.

Add 2 textfields, 2 buttons and provide name and placeholder text as shown below.

Select these controls and embed them inside a View by navigating to Editor menu -> Embed -> View

Now change the background colour of the View and buttons to dark gray and orange.

Select the Embedded View, click Align option and make the View centre align to both Horizontal and Vertical to the Container.

Also add the width and height constraints for the Embedded View keeping the current value.

Now you might see a dashed orange colour line indicating the view is in misplaced position. You can fix this by selecting Update Frame under Resolve Auto Layout Issues option. Please make sure to select Update Frame option under Selected Views and not the container

Previewing the screen in both portrait and landscape should look as shown below

We have seen an introduction to Auto Layout using Storyboard. You can also add constraints via code using NSLayoutConstraint API or Visual Formatting language.

If you need any assistance in Auto Layout, check out our new iOS 9 Auto Layout Tutorials.

Download the source from GitHub

How to use Outlook as a RSS reader

By Ravi Shankar 9 Comments

There are lot of RSS readers available but if you have already installed Microsoft Outlook (Outlook 2013, Outlook 2010 and Outlook 2007) then you can use that as a RSS reader. Listed below are the steps to add and read RSS feeds In Outlook 2013, Outlook 2010 and Outlook 2007

In Outlook 2013 and Outlook 2010, Click the File menu –> Info and click on the Account Settings

In Outlook 2007, Click the Tools menu and select Account Settings

Account Settings in Outlook

Navigate to RSS feeds tab and click on New link

Add RSS feeds in Outlook 2013, Outlook 2010, Outlook 2007

Enter the RSS feed of a blog or a website. In this example, I am going to enter this tech blog RSS feed.

image

Click on the Add button to add the RSS feed. The following RSS Feed Options dialog box would be displayed and if you want to change the delivery location of the RSS feed then click on the Change Folder button and specify the desired location. Click Ok to confirm the changes.

Configure RSS feeds options in Outlook

Navigate to RSS Feed delivery location, this would display the RSS feeds from the configured tech blog

Outlook 2013, Outlook 2010 and Outlook 2007 as RSS Reader

How to share RSS feeds in Outlook 2013, Outlook 2010 and Outlook 2007

If you want to quickly mail the configured RSS feed to your email contacts then you can follow the below mentioned steps.

You can share the feed using the Share This Feed option available as part of Context menu or using Office Ribbon

Context menu – Right click on the any one feed post and select Share This feed option from the menu list.

Conext Menu Share This Feed

Office Ribbon – Select the feed that you want to share then navigate to RSS section under Home menu and click the Share This Feed option.

Office Ribbon - Share This Feed

This would launch the following Share RSS Feed window where you can enter the recipients email address and email them the feed details.

Share This Feed Window in Outlook 2010

Also See: How to configure RSS feeds from YouTube channel in Outlook 2013

  1. Pages:
  2. «
  3. 1
  4. ...
  5. 10
  6. 11
  7. 12
  8. 13
  9. 14
  10. 15
  11. 16
  12. ...
  13. 38
  14. »
« Previous Page
Next Page »

Copyright 2023 © rshankar.com

Terms and Conditions - Privacy Policy