How to tint an UIImageView Image

I continue to explore a few of the basics around using UIImageView and Swift to create interface elements.  In this post I will discuss how you can apply a tint to an UIImageView image.  The example I will use to show the image tint is to toggle on and off the selected state of a favorite “star” icon as shown below.

demo

There are many techniques for applying a tint to an image.  In this example, I’ll discuss the two approaches I like to use.

Just add two lines of code…

The easiest way to apply a tint to an UIImageView image is to set the imageWithRenderingMode of the image to AlwayTemplate and then apply a tint.  This only takes two lines of code to get the desired results.  The below snippet shows how to turn the UIImageView image blue.

myImageView.image = myImageView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
myImageView.tintColor = UIColor.blueColor()

Or use an extension

Coding your image tint operations inline as discussed above works for most cases.  If you have a large number of image elements or different use cases you might want to explore using an extension method.  An extension method allows you to encapsulate the tint operating and make your code more readable.  For example, the snippet below turns the UIImageView image blue in just one line.

myImageView.tintImageColor(UIColor.blueColor())

To accomplish this we added the UIImageView+ImageTint extension to our project.  This extension simply encapsulates our inline code from above in a convenience method named tintImageColor.  The full extension method is shown below.

extension UIImageView {
    func tintImageColor(color : UIColor) {
        self.image = self.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
        self.tintColor = color
    } 
}

You can also find the extension method on Github here.

An example of both…

I’ve put together an example project ImageViewTintImage-Example here that walks you through how to apply both of these techniques to star and unstar UI elements.

Spinning UIImageView using Swift

Recently I’ve been exploring Swift and really been enjoying both the syntax and extension points.  Although still getting my legs under me with Swift and interface builder it has been a great deal of fun. For a recent project, I had to provide a subtle progress cue when the application was synchronizing information.  This cue was accomplished by simply replacing the UIImage of our existing UIImageView, then rotating the UIImageView using CABasicAnimation.  The below shows the end result in action.

ImageViewSpin

Rotation Extension – UIView+Rotation.swift

A majority of the logic behind this rotation effect is encapsulated in the UIView+Rotation extension class shown below.  The following shows the full extension method.  You can also view the extension method on github here.

extension UIView {
    func startRotating(duration: Double = 1) {
        let kAnimationKey = "rotation"
        
        if self.layer.animationForKey(kAnimationKey) == nil {
            let animate = CABasicAnimation(keyPath: "transform.rotation")
            animate.duration = duration
            animate.repeatCount = Float.infinity            
            animate.fromValue = 0.0
            animate.toValue = Float(M_PI * 2.0)
            self.layer.addAnimation(animate, forKey: kAnimationKey)
        }
    }
    func stopRotating() {
        let kAnimationKey = "rotation"
        
        if self.layer.animationForKey(kAnimationKey) != nil {
            self.layer.removeAnimationForKey(kAnimationKey)
        }
    }
}

Start Rotating

The first step in starting the rotation animation is to replace the existing UIImage with the one we will be animating.  In our case we do this by loading an image from our Asset Catalog, as shown below.

syncImage.image = UIImage(named:”sync-spinning”)

Next, since we have the UIView+Rotation extension method added to your project, you simply have to call the startRotating method on your UIImageView to start animating the UIImageView.  The following shows how to call the startRotating extension method.

syncImage.startRotating();

In our example project, we have encapsulated this into the startSpinning shown below.

func startSpinning() {
    syncImage.image = UIImage(named:"sync-spinning")
    syncImage.startRotating()
}

Stop Rotating

The process of stopping the animation is similar to that of starting the rotation process.  First we stop the rotation animation of the UIImageView by calling the stopRotating extension method as shown below.

syncImage.stopRotating()

Next, we replace the UIImage with our initial non rotating image.  As shown below we do this by loading an image from the Asset Catalog.

syncImage.image = UIImage(named:”sync-not-spinning”)

In our example project, we have encapsulated this into the stopSpinning shown below.

func stopSpinning() {
    syncImage.stopRotating()
    syncImage.image = UIImage(named:"sync-not-spinning")
}

Ok, so show me the code

The following shows the code used to call both the start and stop rotating animations. For demonstration purposes, a delay is added to trigger the stop rotating event to illustrate the full animation life cycle.

func startSpinning() {
    syncImage.image = UIImage(named:"sync-spinning")
    syncImage.startRotating()
}

func stopSpinning() {
    syncImage.stopRotating()
    syncImage.image = UIImage(named:"sync-not-spinning")
}

func handleSyncTap(sender: UITapGestureRecognizer? = nil) {
    startSpinning()

    let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(3 * Double(NSEC_PER_SEC)))
    
    dispatch_after(dispatchTime, dispatch_get_main_queue(), {
        self.stopSpinning()
    })
}

A full working example of how to create a rotating UIImageView is available on github at https://github.com/benbahrenburg/SpinningImageView-Example

Walk Through

The following video tutorial walks through the UIImageView rotation example in great detail outlining everything from how the Storyboard UI elements are created through the UIGestureRecognizers added to trigger the rotation animations.

App Transport Security and LocalHost

With iOS9 and OS X 10.11 Apple has introduced App Transport Security which requires a secure connection be made for all NSURLSession connections.  While this encourages developers to use best practices for secure connections this can create interesting side effects if you are using an embedded web server.

If you are using an embedded web service like the excellent GCDWebServer project and target iOS9 you will see the following messages in your Xcode console:

WebServer booted: http://localhost:12344/
2015-07-18 20:34:07.372 myApp[615:6289] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file.

To work around this problem you need to create an NSExceptionDomains for localhost in your application’s Info.plist.  As of iOS9 beta 3 the following Info.plist entries allows your application’s UIWebView or WKWebView to use localhost to access your embedded web server.

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSExceptionDomains</key>
   <dict>
       <key>localhost</key>
       <dict>
       	<key>NSTemporaryExceptionAllowsInsecureHTTPSLoads</key>
           <false/>        	
           <key>NSIncludesSubdomains</key>
           <true/>
           <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
           <true/>
           <key>NSTemporaryExceptionMinimumTLSVersion</key>
           <string>1.0</string>
           <key>NSTemporaryExceptionRequiresForwardSecrecy</key>
           <false/>
       </dict>
   </dict>
</dict>

Adding a center button on your iOS Ti.UI.TabGroup

Remember the original “big center button” of the Instagram app?  Although this design language isn’t cutting edge anymore it still can be useful for a class of apps.  In this post we will explore how through a few lines of code you can create a center action button using the Titanium Alloy framework by Appcelerator.

View Code

To get started, first you need to create a Ti.UI.TabGroup with five Ti.UI.Tab’s.  You might notice that only four of the five Ti.UI.Tab’s are visible, but the hidden Ti.UI.Tab is needed to maintain spacing.  In the below snippet I’ve named and labeled each tab by number.  In our case, the third Ti.UI.Tab is the place-holder.

<Alloy>
	<TabGroup id="tbgroup">
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 1">
				<Label>I am Window 1</Label>
			</Window>
		</Tab>
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 2">
				<Label>I am Window 2</Label>
			</Window>
		</Tab>
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 3">
				<Label>I am Window 3</Label>
			</Window>
		</Tab>		
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 4">
				<Label>I am Window 4</Label>
			</Window>
		</Tab>	
		<Tab icon="KS_nav_views.png">
			<Window title="Tab 5">
				<Label>I am Window 5</Label>
			</Window>
		</Tab>			
	</TabGroup>
</Alloy>


Controller Code

Next alittle controller magic is needed.  Since Alloy does not allow for a Ti.UI.Button to be added to a Ti.UI.TabGroup in our view xml we need to do this programmatically in the controller.  The following snippet shows how a Ti.UI.Button named btnAction is created then added to the Ti.UI.TabGroup

var btnAction = Ti.UI.createButton({
	title:"I'm a button",
	backgroundColor:"#e7e7e8",
	width:85, height:55, bottom:0, borderColor:"#999"
});
 
$.tbgroup.add(btnAction);
$.tbgroup.open();

Since no position is provided, Titanium will automatically center the btnAction control within the boundary of the Ti.UI.TabGroup it is attached.  You just need to make sure the Ti.UI.Button you are attaching is larger then the Ti.UI.Tab place-holder in order to avoid incorrect touch events from firing.

What will we end up with?

The combination of the view and controller code creates the following screen with an oversized center action button.  Since these are just Titanium UI components you can style them and use event listeners as needed.

center-button-tabgroup

Adding a Swift Bridge Header manually

Change are if you are using Swift for more then “Hello World” you will need to interact with existing Objective-C libraries such as FMDB, FCModel, MMWormhole, or something similar.  Although Apple has come great documentation and there is a WWDC video discussing this I thought it might be helpful to walk through my experiences as someone new to Swift.

As I do most of my mobile development around the native aspects of the Titanium framework, I thought it would be interesting to explore writing native extensions in both Objective-C and Swift.  So as part of the Ti.Wormhole project, I provided examples in both languages.  Since the MMWormhole project which Ti.Wormhole is based upon is written in Objective-C, a bridging header is required to talk between the Swift extension and the wormhole.

The first step in creating the bridging header is to add a header file to your project.  This is just like adding any other header file, just using the [MyProjectName]-Bridging-Header.h naming contention.  If you haven’t done this before, in Xcode select File –> New –> File… from the menu then select Header File as shown below.

create-h

Then press Next and enter the name of your bridging header. This needs to be done in the [MyProjectName]-Bridging-Header.h, in the following screenshot this is shown as TodaySwift-Bridging-Header to match our extension name.  If you have multiple targets like in the WormholeExample project you will want to select the correct Target or Targets to apply.  I also found that the bridging header likes to be in the root of your project, so would recommend avoiding placing the file in a nested directory.  After verifying your Targets, Naming, and placement, press the Create button to continue.

create-header

You will now have a file with contents similar to the below.  To allow Swift to access your Objective-C libraries you just need to #import the headers for your libraries as shown below with the MMWormholeClient.h.

bridge-header

Next you will need to update your Target’s Build Settings to reference your Bridging Header.  This is done by opening the Building Settings tab in Xcode and scrolling down to the Swift Compiler section.  Here you want to update the Install Objective-C Compatibility Header option to Yes and enter the name of your Bridging Header file into the Objective-C bridging Header option as shown below.

build-setting

You are almost ready to start using your Objective-C libraries from Swift.  The very last thing you need to do is import Foundation at the top of the Swift file you are using to reference Objective-C.  This is demonstrated in the example project Swift file here and illustrated in the screenshot below.

import

Event Sharing between Titanium, iOS Extensions, and the Apple Watch

JavaScript style events are one of the features I miss most when building native applications.  The fact that Titanium allows for this on mobile is one of things I enjoy most about the platform.  When Appcelerator introduced the ability to create native extensions in version 3.5.x, I began to explore how to pass information through between native iOS extensions and a Titanium application.

In the native world, Mutual Mobile solved this with their MMWormhole project.  MMWormhole uses the Darwin Notifications and your application’s shared directory to pass messages between your app and your extensions.  This seemed exactly what was needed to create events between your Titanium app and extension (or Watch Apps).

After some experimentation and hacking, a Titanium friendly version of MMWormhole called Ti.Wormhole as created.  This allows for events to be published/subscribed between native extensions and your Titanium app.  This is done through a native Wormhole client that you add to your native extension communicating with a native Titanium module installed within your app.

Ti.Wormhole in Action

The following video shows a quick walk through of the Ti.Wormhole running in the iOS simulator.

Before you get started

Before you get started, this development approach requires you program largely in native ( Objective-C or Swift ).  So if you are not comfortable in Xcode, you might want to explore another alternative.  Next, you will need a nightly build of Titanium 3.5.x or greater.

How does it work?

The mechanics are of Ti.Wormhole are straightforward.  Messages are passed from MMWormhole in your Titanium app using a native module to your native extension.  In your native extension another version of MMWormhole  receives your messages providing you the information passed from your Titanium app.  All Ti.Wormhole really does it make MMWormhole work nicely with Titanium.

overview

Native Extension to Titanium

The process of sending events from your native extension to Titanium is relatively straightforward.  First you need to create your native extension… and yes you do this completely native without any JavaScript or Titanium helpers.  Next add the MMWormholeClient classes to your project.  These will give you all of the helpers you need to talk to your Titanium app.  Next you add the Ti.Wormhole module to your Titanium project. This enables your Titanium project to end/receive notifications.

Native to Titanium

Your native extension will publish notifications that will later be turned into Titanium JavaScript events.  The following diagram illustrates the end to end process for doing so.

native-to-ti

A diagram is great but how does this actually work?  Well… to broadcast events from your extension to a Titanium app the first thing you need to do is to create an instance of the MMWormholeClient class.  This class is one half of the bridge you need between your Titanium app and extension.  The below shows how to create this class in both Objective-C and Swift.  The key thing to remember, is the GroupIdentifier and Directory need to match the parameters use by the Titanium module. Otherwise your messages will not be received.

Objective-C Example:

objc-init

Swift Example:

swift-init

Next your native extension needs to send a notification. This is done using the passMessageObject function of the MMWormholeClient class.  The important thing to remember here is that the identifier provided, needs to be the same as the event you are listening to in your Titanium app.  In the below example we are broadcasting to an event named wormEvent.

Objective-C Example:

objc-post

Swift Example:

swift-post

That is all we need to do from our native extension, the rest will be done in our Titanium app.

The first thing we need to do in our Titanium app is to require an instance of the Ti.Wormhole module.


var wormhole = require('ti.wormhole');

Next we use the start method to configure the module to interact with the MMWormholeClient class in our native extension.  The key thing to remember here is that the suiteName and directory need to match the parameters used to create the MMWormholeClient class instance in your extension.

wormhole.start({
      suiteName:"Your suite identifier",
      directory:"Your message directory"
});

Finally, you just need to use the addWormhole method to create an event listener.  This will listen for a specific event and generate a callback when it is triggered.

wormhole.addWormhole("wormEvent",function(e){
    console.log("Event in ti app: " + JSON.stringify(e));
});

Titanium to Native

It is just as easy to go from Titanium to Native.  The following diagrams the end to end process that is used in sending messages from Titanium to your native extension.

ti-to-native

I know what you are thinking, another diagram great, show me the code.  To save time we will skip over the requiring the Ti.Wormhole module and calling Start method. This would be the same as the Native to Titanium example.

The first step is to send a message from Titanium using the Ti.Wormhole module’s post method as shown below.  Since you will want to background your app and access notification center, you might want to use setTimeout to give yourself a few seconds.

setTimeout(function(){
     wormhole.post("wormEvent",{displayNumber:displayCount});
},10000);

By calling post, a message is placed into the notification queue to be picked up by your native extension.  To receive these notifications you need to add a listener in your native extension as shown in the following Objective-C and Swift examples.

Objective-C Example:

objc-listen

Swift Example:

swift-listen

Examples

The Ti.Wormhole project has examples written in both Objective-C and Swift.  You can see video overview of the project here.  Everything else is at https://github.com/benbahrenburg/Ti.Wormhole.

Embedding Swift in your Objective-C app, solving the libswiftCore.dylib error

Lately I’ve been experimenting with using Swift in my Titanium projects.  Since Titanium is really just a Objective-C app under the covers it is fairly straight forward to mix and match Swift within your project.

I did encounter one surprise the first time I added a Swift module or extension to my project.  Even though the extension or module compiles without issue, as soon as it was added to my Titanium project I started to receive errors similar to dyld: Library not loaded: @path/libswiftCore.dylib.  The root cause was surprising, it seems that Xcode 6.2 does not enable the “Embedded Content Contains Swift Code” Build Setting by default for Swift extension projects.

If you are building Swift extensions for Titanium or any other Objective-C application make sure you update your project to include this.  To do this, go to your Swift Target’s Build Settings, then Build Options.  Alternatively you can just search for embed to find the correct option.  Once you have located the setting you need to toggle the “Embedded Content Contains Swift Code” from No to Yes as illustrated below.

xcode-swift-embedded

Using iOS Visit Events in Titanium

It seems every app has its own way to handle Geo Location.  In many of my cases, your destination is more important then your journey. In iOS 8 Apple provides the CLVisit API specifically designed to provide this type of functionality.  Events are generated when you arrive to a location, and another is generated when you leave.  This provides a very battery friendly approach to solving place based Geo Location problems.

So how do you use this in Titanium?  Like almost any other Titanium requirement you run into there is a module already available.  You can download the Ti.GeoVisits module to use this functionality today.  I used the example app.js for a week and found that the Visit event fired reliably after I was in a single location for more then 10 minutes and about 5 minutes after leaving a location.  This wait time does cause for quick stops such as picking up take away to be missed.  Although this approach has trade offs, it virtually has no impact on battery life.

Below is a record of my tests over the last 9 days.  I’d encourage you to try the same test yourself.  As simulator testing isn’t really a meaningful option for Geo Location apps, I would suggest installing the example app.js and heading out to do a few errands.

Results for the last 9 days:

IMG_0214

What does the Ti.GeoVisits API look like?

The full Ti.GeoVisits API is very small consisting of only three methods and four events.  The below snippet summaries all of these.  For full documentation please visit here for details.

var visits = require('ti.geovisits');
//Fired when Ti.GeoVisits starts
visits.addEventListener('started',function(e){});
//Fired when Ti.GeoVisits stops
visits.addEventListener('stopped',function(e){});
//Fired when Ti.GeoVisits errors
visits.addEventListener('errored',function(e){});
//Fired when Ti.GeoVisits registers a place visited or left
visits.addEventListener('visited',function(e){});

//Boolean indicating if module supported
visits.isSupported()

//Method used to start monitoring for visits
visits.startMonitoring();

//Method used to stop monitoring visits
visits.stopMonitoring();

Learn more about Ti.GeoVisits on Github at https://github.com/benbahrenburg/Ti.GeoVisits.

You can also download the module GitTio at http://gitt.io/component/ti.geovisits

Titanium Charting with JBChartView

How to use Charts on mobile is one of those areas where everyone has an opinion.  Usually these approaches boil down to the use of a WebView or taking a dependency on a 3rd party native framework.

Usually I recommend using a WebView as the web charting tools tend to provide a greater level of functionality. But recently I discovered JBChartView by Jawbone which changed my mind.  JBChartView  provides charting functionality I typically use bundled in an easy to use native iOS (sorry not android version) project.

To make JBChartView consumable by Titanium I’ve wrapped the project into a module, Ti.JBChart , and created Titanium specific documentation and examples.  The below animated gif shows the Ti.JBChart examples in action.

In Action

An example

The Ti.JBChart  github project has examples for Bar, Line, and Area charts.   The following snippet shows an example on how to use the LineChartView in your Titanium project.

    function createData(){
        var result =[];
        function createRandom(min,max){
            return Math.floor(Math.random()*(max-min+1)+min);
        }   
        for (var iLoop=0;iLoop<12;iLoop++){
            result.push(createRandom(1,12));
        }
        return result;
    }

    var data = [];
    //Add first line chart
    data.push(createData());
    //Add second line chart
    data.push(createData());

    var myStyles = [];
    //Create the first line chart with a solid  line
    myStyles.push(chart.CHART_LINE_SOLID);
    //Create the second line chart as a with a dashed line
    myStyles.push(chart.CHART_LINE_DASHED);

    var lineChart = chart.createLineChartView({
        width:Ti.UI.FILL, height:250, 
        data : data,
        toolTipData : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
        selectedLineColors :['yellow','orange'],
        lineColors:['green','blue'],
        styles : myStyles,
        selectionBarColor:'purple',
        chartBackgroundColor:'#404041'
    });

Looking for more?

Fixing iOS module build.py permissions

Starting with Titanium 3.3.0.GA Appcelerator has updated their module templates to have a new default folder structure.  Along with these directory changes you will notice that you get a permission error when running the ./build.py script, usually something like the error shown below.

build-1

To fix this you simply need to run the chmod 755 build.py command in terminal as shown below.

build-2

This updates build.py to have the correct permissions so that you can continue your building by running build.py as you’ve always done.

build-3