Posts Tagged ‘iPhone’

Exploring iOS 7 Rounded Corners

Thursday, June 20th, 2013

Apple announced iOS 7 at the WWDC 2013. Compared to the previous iOS versions it gets a whole new look for the first time. There’s a lot of discussion going on whether it’s good or bad design. I personally like it very much, and it reminds me a bit of the huge step from Mac OS 9 to Mac OS X years ago. Many things have changed in iOS 7, but one little detail attracted my attention and that’s what this article is about: rounded corners. Apple is very obsessed about every little detail; in my opinion that’s one of the secrets why they make so beautiful and successful products. Usually a rounded corner is just a quarter of a circle, one might think. But Apple changed the form factor of rounded corners in iOS 7. Here is a little comparison:

Rounded Corners in iOS 6Rounded Corners in iOS 7


Animated iOS 6 vs 7 Comparison


To me, the corners in iOS 7 look much smoother and organic. These new corners are everywhere in iOS 7. One reason for this is that as a developer you get these new corners for free. Whenever you use the existing functions of the operating system to create rounded corners, you get the improved ones in iOS 7, e. g. when calling [UIBezierPath bezierPathWithRoundedRect:cornerRadius:].

Here is an image that shows the difference between the old and the new corners:

Corner Difference between iOS 6 and iOS 7


You see that not many pixels have changed, even at this big size, but nevertheless it has some subtle but perceptible impact in how the corners look and feel.

Currently there are a few discussions on how Apple draws these new corners; even some mathematical equations are published. I took a rather pragmatic approach to analyze it: I created a small test app that lets the system create a rounded rectangle and then introspects and visualizes the elements of the returned bezier path. Then I launched this app on iOS 6 and iOS 7. Here are the results:

Rounded Corner Bezier Path on iOS 6
Rounded Corner Bezier Path on iOS 7
A red cross marks every point where a straight line is drawn to. An orange cross with two green control points in between define a bezier curve. As you can see there are four little points where the path is not perfect yet: there are four (very) short straight lines from a curve end point (orange) to a new point (red) very closely together. These unnecessary four short lines can be stripped out of the path; maybe this will be fixed in the final version of iOS 7.

What’s also interesting is the fact that the edges of the rectangle are bent much earlier than before. In the picture below the blue area is where the lines are curved in iOS 6. The red area is where the lines are curved in iOS 7. It’s more than half the corner radius earlier:

Line bending areas

Update: Together with @flarup and @marcedwards we tried to figure out the exact radius for the corners being used for the app icons in iOS 7. Additionally I filtered out the annoying short lines metioned above and exported the UIBezierPath as SVG file. As far as we can see a radius of 27 pixels at 120×120 pixel icon size produces a pretty good match. Download it here.

In case you wonder how I introspected the UIBezierPath to draw the images above – here is the UIView code:

@interface CornerTestView ()
@property (nonatomic) CGPoint previousPoint;
@end

@implementation CornerTestView

static void pathInspector(void *info, const CGPathElement *element)
{
	CornerTestView *view = (__bridge CornerTestView *)info;
	[view addElement:element];
}

- (void)drawRect:(CGRect)dirtyRect
{
	[[UIColor whiteColor] setFill];
	UIRectFill(dirtyRect);

	CGRect rect = self.bounds;
	CGFloat size = MIN(CGRectGetWidth(rect), CGRectGetHeight(rect)) - 20;
	size = round(size / 2) * 2;
	rect = CGRectMake(round(CGRectGetMidX(rect) - size / 2), round(CGRectGetMidY(rect) - size / 2), size, size);
	CGFloat radius = size / 4;
	UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
	[[UIColor colorWithRed:0.90 green:0.93 blue:1.0 alpha:1.0] setFill];
	[path fill];

	CGPathRef cgPath = path.CGPath;
	CGPathApply(cgPath, (__bridge void *)(self), pathInspector);
}

static UIBezierPath *crossAtPoint(CGPoint p)
{
	UIBezierPath *cross = [UIBezierPath bezierPath];
	cross.lineWidth = 0.5;
	[cross moveToPoint:CGPointMake(p.x - 2, p.y - 2)];
	[cross addLineToPoint:CGPointMake(p.x + 2, p.y + 2)];
	[cross moveToPoint:CGPointMake(p.x - 2, p.y + 2)];
	[cross addLineToPoint:CGPointMake(p.x + 2, p.y - 2)];
	return cross;
}

- (void)addElement:(const CGPathElement *)element
{
	switch (element->type) {
		case kCGPathElementMoveToPoint:
			[[UIColor grayColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			self.previousPoint = element->points[0];
			break;
		case kCGPathElementAddLineToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line stroke];

			[[UIColor redColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			self.previousPoint = element->points[0];
		}
			break;
		case kCGPathElementAddQuadCurveToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line addLineToPoint:element->points[1]];
			[line stroke];
			[[UIColor cyanColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			[[UIColor magentaColor] setStroke];
			[crossAtPoint(element->points[1]) stroke];
			self.previousPoint = element->points[1];
		}
			break;
		case kCGPathElementAddCurveToPoint:
		{
			UIBezierPath *line = [UIBezierPath bezierPath];
			line.lineWidth = 0.25;
			[[UIColor lightGrayColor] setStroke];
			[line moveToPoint:self.previousPoint];
			[line addLineToPoint:element->points[0]];
			[line addLineToPoint:element->points[1]];
			[line addLineToPoint:element->points[2]];
			[line stroke];
			[[UIColor greenColor] setStroke];
			[crossAtPoint(element->points[0]) stroke];
			[crossAtPoint(element->points[1]) stroke];
			[[UIColor orangeColor] setStroke];
			[crossAtPoint(element->points[2]) stroke];
			self.previousPoint = element->points[2];
		}
			break;
		case kCGPathElementCloseSubpath:
			break;
	}
}

@end

Have fun!

CoreFoundation plus QuickTime on Windows

Monday, April 26th, 2010

We are writing portable cross-platform software, primarily running on Macs, Windows PCs, iPhones and iPads. Recently we had a problem to solve, that I’ll describe here.

Our code uses Apple’s CoreFoundation. On Mac OS X or iPhone OS it’s “just there” as part of the System Frameworks, and on Windows we use CoreFoundation in form of the great OpenCFLite port. Now we had a project where we’re also using Apple’s QuickTime. Again, on the Mac it’s “just there”, but on Windows we have to use the QuickTime SDK for Windows. Now when trying to build this project that uses both CoreFoundation and QuickTime on Windows, we got a lot of Linker errors complaining about duplicate symbols. The reason is that the QuickTime SDK for Windows itself contains its own subset of CoreFoundation. So we searched for a solution.

I already had the idea to write a wrapper around all necessary QuickTime calls and move this wrapper into a DLL to separate the QuickTime stuff from the main binary. So QuickTime called from the wrapper DLL uses its own embedded CoreFoundation implementation, and the main binary can still use OpenCFLite. Most probably there are some things to keep in mind, e.g. the API to the QuickTime wrapper must not pass any CoreFoundation objects across the boundary. CFStringRefs had to be passed e.g. as plain C strings UTF-8 encoded and the CFStringRef has then to be reconstructed from that inside the wrapper. But all this shouldn’t be much of a problem.

But we were not 100% sure if our theory really solves the problem, or wether there is an easier solution. Maybe some secret linking tricks or something like that.

We thought somebody else must already had the same problem!? And, yes, it came to my mind that the developers of WebKit – the engine of Apple’s web browser Safari – must have solved that. I know that WebKit uses CoreFoundation. And I also was pretty sure that WebKit uses QuickTime for displaying Video. Luckily WebKit is open source, so I downloaded the WebKit sources and digged into them to see if the WebKit engineers had the same problem and how they solved it.

Short time later I had the answer. Really, they obviously are in the same boat. And it was solved pretty much the same way as the idea that I already had in my mind. WebKit contains classes like “QTMovieWin” that are build into a separate DLL. So all QuickTime calls are done in those special wrapper classes from the DLL and WebKit itself does not directly call any QuickTime routines.

It’s always nice to see being not the only one having strange problems to solve. 😉

I published this article, because I googled a lot for CoreFoundation and QuickTime linking conflicts on Windows, but nobody seems to either have this constellation or did not write or ask about it. Maybe this article will help somebody out there …

Building Boost for the iPhone

Wednesday, May 6th, 2009

We’re working on very interesting stuff for new products behind the scenes. It’s a special challenge to write cross platform code. For that reason we are creating a very solid code base that we can reuse in all future products. We decided to use C++ and wanted to support Mac OS X, Windows, iPhone OS and potentually Linux. Maybe I’ll write more about our concepts and decisions about that in a future post, but for now I’ll concentrate on Boost.

Boost is a collection of free cross platform and high-quality C++ libraries. Most of the classes can be used “header only”, so you include the appropriate header file in your code and it “just works”. Maybe the most famous class of Boost is the Smart Pointer class shared_ptr. In our case we also needed the compiled libraries of Boost. Therefore we had to compile it amongst others for the iPhone. There are a few difficulties when building it for the iPhone and I had to google a lot until I found out all the details. Now I want to share my solution how I managed to build the Boost libraries for the iPhone – and here it is. I tried it with Boost version 1.42.0:

  1. You need a Mac with Mac OS X and installed iPhone SDK, of course.
  2. Download the Boost sources and extract them somewhere on your hard disc.
  3. In the directory with the Boost sources, open the file tools/build/v2/user-config.jam and fill it with the following content:

    using darwin : 4.2.1~iphone
       :
    /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/g++-4.2
       : <striper>
       : <architecture>arm <target-os>iphone <macosx-version>iphone-3.0
       ;

    using darwin : 4.2.1~iphonesim
       :
    /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/g++-4.2
       : <striper>
       : <architecture>x86 <target-os>iphone <macosx-version>iphonesim-3.0
       ;

    You have to adjust the paths if you have installed the iPhone SDK at a different location.

  4. Now open the file tools/build/v2/tools/darwin.jam and add the missing line

    iphone-3.1.3 iphonesim-3.1.3

  5. To build the Boost libraries for the iPhone Device, do the following:

    bjam --prefix=/path/for/BoostiPhoneDeviceLibs --layout=versioned toolset=darwin architecture=arm target-os=iphone macosx-version=iphone-3.0 define=_LITTLE_ENDIAN link=static install

    Replace /path/for/BoostiPhoneDeviceLibs with the path were you want to have the final Boost libraries and headers located.

  6. To build the Boost libraries for the Simulator, do the following:

    bjam --prefix=/path/for/BoostiPhoneSimulatorLibs --layout=versioned toolset=darwin architecture=x86 target-os=iphone macosx-version=iphonesim-3.0 link=static install

    Replace /path/for/BoostiPhoneSimulatorLibs with the path were you want to have the final Boost libraries and headers located.

Unfortunately there are a few errors and warnings when building Boost for the iPhone this way. But because we currently do not use the affected classes yet, we did not spend much time into that.

Being Rejected. Not.

Thursday, March 12th, 2009

Here’s another story of an application being rejected by Apple from the App Store.

“Hey, you have an iPhone! – Can I take a look?”

Do you know that? This situation gave me the idea for a funny application that should display the Home screen of your iPhone or iPod touch, but as soon as someone touches it, a scary barking dog should appear. The idea for my little funny “Watchdog” application was born.

I developed it, polished it until I liked it much, wrote a description, created a web page etc. and finally submitted my iPhone application to Apple so they can review it and put it into their App Store.

Round One

On my first submitting attempt the Watchdog application contained real screenshots of the Home screen of the iPhone and the iPod touch in all available languages (blowing up the application size to about 7 MB). I already had the feeling that Apple will reject this because with the screenshots I indirectly use their icon graphics, but nevertheless I tried it. OK, my app really got rejected the first time.

Apple’s official answer was:

Unfortunately, your application, Watchdog Mobile, cannot be added to the App Store because it uses standard iPhone screen images in a non-standard way, potentially resulting in user confusion. Changing the behavior of standard iPhone graphics, actions, and images, or simulating failures of those graphics, actions, or images is a violation of the iPhone Developer Program agreement which requires applications to abide by the Human Interface Guidelines.

I can understand that Apple does not want screenshots of the Home screen in apps. The statement is still a bit strange, because Apple complains about “potentially resulting in user confusion”. Er … yes … indeed … Watchdog is designed to confuse (or surprise) the user! When someone uses Watchdog, he does it intentionally and after seeing the barking dog it should be obvious to everyone that there is a kind of … uhm … “watchdog” application running. It’s surprising and can be really shocking if you don’t reckon that (it actually happened to myself a few times) but it’s very funny and you realize the joke at the same second.

Round Two

OK, having screenshots of the Home screen containing Apple icons in an application is really a bad idea. So I added the ability to choose a custom image and wrote a description how the user can make a screenshot of his Home screen. Unfortunately this decreases the ease-of-use of the application a little bit, but it’s not really dramatic. I removed all bundled screenshots and created a funny comic styled “Fake Home screen” that is used as default image. As a side note, the size of the app reduced to around 1.5 MB.

But guess what … the second version of my application got rejected again. Apple’s statement was that “the modified iPhone screen image is still too similar to the iPhone screen image”. Argh. OK, I know there are different types of people … some are more “visual”, others are more “auditory” and others more “tactile” oriented. Maybe people that are not so “visual” may still confuse the comic styled Home screen with a real Home screen. By the way, I really like the big funny icons and once I saw them on the iPhone screen I wished they could be used for real. 😉

Round Three

I though about what I can use as default image instead. My first idea was to use a cute looking puppy. Perhaps with a sign around its neck saying something like “Replace me” or so. While this might be a bit funny, I did not want to get too far away from the original idea to present a Home screen. So I came up with a modified version of my comic styled Home screen: I dimmed it in brightness and put a very flashy text above it saying that it’s a Fake Home screen. So nobody can ever confuse this with a real Home screen. I was very curious about the reaction from Apple.

But – I was already prepared for that – Apple rejected it again. “Simulating failures” is obviously not accepted by Apple. At some degree I understand that, but I thought it’s obvious enough that no-one gets “potentially confused” by this application. Thought wrong.

Round Four

So I prepared my last attempt before giving up. I completely threw away the idea of simulating a Home screen. Let’s just make a dog application and let’s hope that the user has the idea of using a Home screen image for himself. I removed every comment about the Home screen from the application and its description. I replaced the Default image with a neat looking dog. I completely rewrote the description. There’s nothing of the original idea in this app. Of course, the user can still use a screenshot of the Home screen to have the original effect, but it’s not so obvious anymore. This time is took much longer for Apple to review this app … but finally …

Hooray – Apple accepted my Watchdog application! 🙂

Feel free to purchase Watchdog at the iPhone App Store and tell everybody how cool that thing can be used. 😉 Thank you very much for your support!

To get the best effect, you have to create a screenshot of your Home screen. This can be done by quickly pressing and releasing the Sleep/Wake and Home buttons at the same time while the Home screen is displayed. The screenshot ends up in the “Camera Roll” section of the Photo application on the iPhone. Then just choose this image in the Watchdog application. Have fun!

Finally a little gallery of the four different versions of the default image that I have created:

Evolution of the Default Image

Evolution of the Default Image

The Art of the Camel

Monday, January 26th, 2009

This weekend my first iPhone / iPod touch game Sahara found its way into the App Store.

Sahara is a challenging puzzle game where you have to guide a camel through a labyrinth in the desert. If you like it, you can purchase it in the App Store.

I am very happy about that release of my first iPhone app. It was very exciting and fun to do all those things like registering as iPhone Application Developer, signing all the contracts, exploring the iPhone SDK, developing the game e.g. programming an algorithm to find the shortest way through the maze, implementing animations, doing all the graphics and sounds, preparing my web site and finally submitting the application to Apple. It went through the review process in just about two days without any problems. It seems I did everything alright. 😉

To give you some insight to the graphical development process of Sahara, here is an example how the camel was born:

Life of the camel

Life of the Camel

At the left is a rough pencil drawing of the camel how it was in my head. I did about five to ten drawings of that style or so. It was not exactly how I thought it should look like, but this one was pretty close. Then I scanned the drawing and did the final artwork directly on my Mac with vector graphics. I put the scan of the draft drawing underneath the image with 50% transparency as orientation. As you can see, I did a lot of corrections especially to the head of the camel. The funny eyes are bigger, the shape of the head is different, the ears are smaller and better aligned and so on. Although I own a Wacom tablet, I did all the graphics with my mouse, because I did no real “drawing”: I added a bunch of bezier paths for each stroke and then I corrected the points and anchors until I was satisfied with the result. Note that I did not have a pencil drawing for the skeleton; I just used the final camel as orientation underneath and drew the bones directly on the computer as vector graphics onto it.

After doing years of “just coding and coding” I really enjoyed doing this artistic work. Although in my opinion developing software is also some sort of artistic work, but I mean artistic in a graphical manner here. I did a lot of drawing in my childhood, but once I got my first computer it was displaced by programming so far. I am happy that I can combine both now.

Finally some more studies used for developing the camel for the game:

Study of the Camel

Studying the Camel

Welcome

Monday, January 12th, 2009

I think it’s time to start a blog.

In this first blog entry I’ll introduce myself and reveal some internals. Don’t worry, the next blog entries will be about other stuff, like things that I find interesting, news and background information about my products, maybe some technical articles about programming, some fun stuff etc.

My name is Manfred Schwind, I am living in Germany and I started mani.de long time ago in the year 1998. While still going to college at that time I’ve done a lot of programming in my spare time for the Atari ST (anyone still knows jinnee?) and later for the Macintosh. My biggest project so far is iVolume, a very successful software to adjust the volume of your iTunes songs. Version 3 of iVolume was rewritten from scratch and for the first time it’s also available for Windows. It has some interesting internals like a fully cross-platform and heavily multi-threaded backend written in C++ and just a very “thin” GUI layer that is the only thing written twice specifically for Mac OS X (written in Cocoa) and for Windows. Maybe I should write one or more blog entries about these things soon. 😉 The Windows specific parts of iVolume were done by Christian Lier who’s currently also working for Enabling Labs.

From 2004 to 2008 I worked at equinux as Mac OS X Software Developer. There I was lead developer of iSale, an eBay selling application that has won two Apple Design Awards ([1], [2]). I also worked on other projects, e.g. major parts of the GUI of VPN Tracker 5 and CoverScout 3.

It was a very interesting and fulfilling time at equinux, but at the end of 2008 I decided to become independent again and do my own stuff. I have never had the heart to give up my private projects, but having two jobs and a family with two kids is simply too much for one person in the long run, so I had to decide for one job. It was not an easy decision, because I had a great time at equinux; it’s a young team of nice people all doing great jobs and we had a lot of fun. But at the end I preferred to do my own things and I’m very happy with that so far.

So currently I am working on new projects, e.g. for the iPhone, and there are some great things coming out soon.

Feel free to subscribe to this blog to keep being up-to-date.