Apr
04

Flickring UIButton State Issue

Ran into a very specific "bug" in my iPhone application today. We have on our about page of the application two images for the highlighted and normal states of a button. It works as expected when you "press" and then "touch up" at a slow pace, but if you click/tap it quickly, there's a noticeable flicker between states. Here's the code inside the subclass of UIButton that creates the buttons:

UIImage *normalImage = [[UIImage imageNamed:@"btn-small.png"] stretchableImageWithLeftCapWidth:10.0f topCapHeight:0.0f];
UIImage *highlightedImage = [[UIImage imageNamed:@"btn-small-down.png"] stretchableImageWithLeftCapWidth:10.0f topCapHeight:0.0f];

[self setBackgroundImage:normalImage forState:UIControlStateNormal];
[self setBackgroundImage:highlightedImage forState:UIControlStateDisabled];
[self setBackgroundImage:highlightedImage forState:UIControlStateHighlighted];

[self setAdjustsImageWhenDisabled:FALSE];
[self setAdjustsImageWhenHighlighted:FALSE];

When a button is tapped it simply disables itself and enables the other button:

- (IBAction)aboutButtonTouched:(id)sender
{
    aboutButton.enabled = FALSE;
    rulesButton.enabled = TRUE;
}

- (IBAction)rulesButtonTouched:(id)sender
{
    rulesButton.enabled = FALSE;
    aboutButton.enabled = TRUE;
}

This works fine, but there's a noticable "flicker" when tapping the button quickly (and not a delicate press, hold, and release). The solution to this flickering took a bit of reverse engineering. The first thing I did was modify the aboutButtonTouched method to log the button's state property which is a bit-mask NSUInteger:

- (IBAction)aboutButtonTouched:(id)sender
{
    rulesButton.enabled = TRUE;
    aboutButton.enabled = FALSE;    
    
    NSLog(@"%d", [sender state]);
}

At this point, the button is disabled through setEnabled, and the log reported that the state was "3". Looking at the bit-mask type for UIControlState (Comments added since I can never remember bitwise):

enum {
   UIControlStateNormal               = 0,            // 0
   UIControlStateHighlighted          = 1 << 0,       // 1
   UIControlStateDisabled             = 1 << 1,       // 2
   UIControlStateSelected             = 1 << 2,       // 4
   UIControlStateApplication          = 0x00FF0000,
   UIControlStateReserved             = 0xFF000000
};

We can see that to get "3" (0011) we should use UIControlStateHighlighted | UIControlStateDisabled (0001|0010 or 1|2), something which I did not have as a state in my original button definition. The key here that there's a brief time when the state is both before only being disabled ("A control enters this state when a touch enters and exits during tracking and and when there is a touch up" -- from the docs). So the final state settings for the button where it does not flicker are:

[self setBackgroundImage:normalImage forState:UIControlStateNormal];
[self setBackgroundImage:highlightedImage forState:UIControlStateDisabled];
[self setBackgroundImage:highlightedImage forState:UIControlStateHighlighted];
[self setBackgroundImage:highlightedImage forState:UIControlStateHighlighted|UIControlStateDisabled];
Mar
23

Hacynth: Spring Sessions Mix

Download Spring Sessions Mix

Listen To Your Heart - Soul Mosaics
Hidden Memories feat. Lilw - Human Factor, T-muniz
Nice Dude With Ice Cream - Kasper
Grapefruit - Donnie Dubson
Up The Mountain - Bomb The Bass, Markey, S.P.Y.
London Express - BrokenDrum
Vice - DatA
Give Me Your Love - Spy, Random Movement, Marky, Miri
Togetherness - Marky, Makoto
Brothers - Redeyes
Good Inside - Jazz Thieves
Paradise - Edward Oberon
Battlecat - Donnie Dubson
Infrasonic - Ulterior Motive, Judda
P-Style - Squash
It Was The Future - Dakosa
Oceans Above Life - Deep Life, ASC
Style Is A Cage - Marginal
Scotch Bonnet - Random Movement
Back In Time - Stunna

Mar
07

Getting Started with Custom Zend_Tool Resources

Recent versions of the Zend Framework come with a useful CLI (command line) tool for manipulating project structure and files called Zend_Tool. Assuming you use a standard framework layout, this tool can speed development by creating controllers, views, models, et al. I found this tool useful, but wanted to extends the tool to make it more custom to my liking. i.e. instead of

zf create controller Articles

outputting a controller that extends Zend_Controller_Action, I want to make a CMS controller builder; one that extends Typeoneerror_Cms_Controller_Crud, sets and creates a model that extends Typeoneerror_Db_ActiveRecord, etc. My intention at the beginning of this was to add a Provider that allowed me to type

zf create crud Articles

and set up all of this. After spending a few hours figuring out where everything was and how it worked, it's pretty clear that ZF Tool is still very much a "baby." Set-up is quite challenging, and you have to write quite a bit of code to make your own providers (providers define your command line actions) and contexts (contexts define resources and how to handle provider actions).  I thought I'd provide some basic steps to get started with your own resources.


Installing the zf tool.

First thing you need to do is install the zf.sh script. This is available in the "bin" directory of the release. I've got my own library with a subversion external to the latest release checked out in it, so I copied the "bin" file into the same directory. So locally I have something like:

/typeoneerror
    /bin
        /zf.php
        /zf.sh
    /library
        /Typeoneerror
        /Zend

Now, the zf scripts need to be in your unix include_path to run. Instead of doing that I added an alias to my .bash_profle that points to the shell script:

alias zf='/Users/ben/Documents/Codebase/taz/trunk/project/bin/zf.sh'

Also, make sure the zf script is executable:

chmod a+x /Users/ben/Documents/Codebase/taz/trunk/project/bin/zf.sh

Now if you run the following command, you should see the version output:

$ zf show version
Zend Framework Version: 1.10.2

In recent versions of zf tool, you have to create a storage directory and configuration file if you want to write any custom contexts or providers. Let's do that next. First run:

$ zf --setup storage-directory
Storage directory created at /Users/ben/.zf/

followed by:

$ zf --setup config-file
Config file written to /Users/ben/.zf.ini

If you open that up you should see that the include path to the Zend library folder has been added because it's where the zf script expects it to be ("../library"). Since my client code in Typeoneerror directory lives there as well, we should be set.

# Inside /Users/ben/.zf.ini
php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"


Custom Resources

Now, to begin creating custom providers, we first need a Manifest. A custom manifest tells the tool what providers to register. Let's create a manifest and a sample provider first:

# Manifest.php

require_once "Typeoneerror/Tool/Provider/Crud.php";

class Typeoneerror_Tool_Manifest implements Zend_Tool_Framework_Manifest_ProviderManifestable
{
    public function getProviders()
    {
        return array(
            new Typeoneerror_Tool_Provider_Crud()
        );
    }
}

All we implement in this file is the getProviders method which returns a list of instantiated providers.

# Crud.php

class Typeoneerror_Tool_Provider_Crud
extends Zend_Tool_Project_Provider_Abstract
implements Zend_Tool_Framework_Provider_Pretendable
{
    public function create($name = 'world')
    {
       $this->_registry->getResponse()
                       ->appendContent("Hello, {$name}!");
    }
}

Our sample defines a create method which simply echos out a "Hello" message
to the CLI output. Before you can actually use these new tools though, we
have to register them with the Reposity. Back to the command line:

$ zf enable config.manifest Typeoneerror_Tool_Manifest
Provider/Manifest 'Typeoneerror_Tool_Manifest' was enabled for usage with Zend Tool.

If you take another look at your config file you'll see something like:

php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"
basicloader.classes.0 = "Typeoneerror_Tool_Manifest"

Next register the Crud provider:

trunk $ zf enable config.provider Typeoneerror_Tool_Provider_Crud
Provider/Manifest 'Typeoneerror_Tool_Provider_Crud' was enabled for usage with Zend Tool.

And check the ini output again

php.include_path = "/Users/ben/Documents/Codebase/taz/trunk/project/library:.:"
basicloader.classes.0 = "Typeoneerror_Tool_Manifest"
basicloader.classes.1 = "Typeoneerror_Tool_Provider_Crud"

This tells the tool to load those classes for use. Theoretically, you could just add these manually to the ini file. Anyway, now we can run our tool!

$ zf create crud
Hello, world!

$ zf create crud Ben
Hello, Ben!

If you run the following you can now see that the Crud controller is registered
with the zf tool.

$ zf show manifest
type=Tool, clientName=all, providerName=Crud    : crud


Custom Output Providers and Contexts

Ok, great, now we can see how to register parts with the zf tool, but now you're wondering (probably)
"how do I create custom output?".

Well, you're going to need to create two classes: a Context (in most cases a "file context" or how to save the file and the code that will be injected into the file) and a Provider which is initialized from the CLI and uses Contexts to create the resources. I found this tutorial to be a good overview of those steps.

To make things easy for my crud controller provider, I simply copied Zend_Tool_Project_Context_Zf_ControllerFile (context) and Zend_Tool_Project_Provider_Controller (provider) and edited the code generation to suit my needs. You can download the sample files I created here. The Provider defines the "create" and "delete" functions which are accessed from the command line. The Provider checks to see if the Crud controller exists and if not, creates it using Zend_CodeGenerator (Typeoneerror_Tool_Context_CrudControllerFile :: getContents).

As I said at the beginning, custom output is a chore, but I feel like this has a load of potential. ZF 1.10 begins the support of "delete" methods with providers as well but they don't seem to be fully complete yet (I implemented a delete method in my crud provider but I'm unsure how to remove the line item in the .zfproject.xml manifest as of yet). You may find yourself manually editing your project manifest as you get going.

Good luck! Feel free to send me a message if you have any tips or questions about Zend_Tool.

Feb
03

Adding CVS-style $Id$ tags to subversion commits

You can automatically add versioning data to your files when you commit with subversion. This is a super helpful way to quickly see when the last update was and which user committed the revision. For example, here's the header of one of my .as files:

/**
 * @author     Benjamin Borowski (ben.borowski@typeoneerror.com)
 * @copyright  Copyright (c) Typeoneerror Studios http://typeoneerror.com
 * @version    $Id: Fetch.as 98 2010-01-31 07:31:11Z ben $
 */

Above you can see version number, date commited and my name as the last person to commit changes to the repository for this file. Adding this "auto-tagging" is quite easy. You simply need to add svn:keywords to the file(s) you're going to commit.

To start, you can do the following (assuming "yourFileName" is the name of the file you want to add the Id keyword to):

$ svn propset svn:keywords Id yourFileName
property 'svn:keywords' set on 'yourFileName'
$ svn propget svn:keywords yourFileName
Id

Now you simply add the Id tag in your file, e.g.:

/**
 * $Id$
 */

Since the Id property is set, when subversion commits, you'll see it updates to the "version" tag in the earlier example.

Now that we know how that works, how about we configure our subversion installation to add this property to files whenever we "svn add" them to our project? Open up ~/.subversion/config in your favorite text editor. You're going to want to make sure the following options are set:

[miscellany]
enable-auto-props = yes

This turns on adding properties automatically when added to working copies. Now under [auto-props], add something like the following. Each of these is just a wildcarded file extension. You may not need all of these; these are just some of the common file-types I deal with:

*.as = svn:keywords=Id
*.css = svn:keywords=Id
*.cpp = svn:keywords=Id
*.email = svn:keywords=Id
*.h = svn:keywords=Id
*.ini = svn:keywords=Id
*.js = svn:keywords=Id
*.m = svn:keywords=Id
*.mm = svn:keywords=Id
*.mxml = svn:keywords=Id
*.php = svn:keywords=Id
*.phtml = svn:keywords=Id
*.pjs = svn:keywords=Id
*.xml = svn:keywords=Id

So now any time I add (for example) MyClass.as or MyViewController.m to a working copy, the Id property is automatically set. To wrap up, here's a bash function you can add to your .bash_profile to add the Id property recursively to files already under version control:

# add svn:keywords Id property recursively
function addSvnId
{
find . \( -name "*.as" -o \
-name "*.php" -o \
-name "*.xml" \) -exec svn propset svn:keywords Id {} \;
}

Of course you can add and remove new extensions. To use this, simply navigate to the working copy in question in Terminal and run:

$ addSvnId

Be careful as this is recursive so it will apply to all files with the specified extensions starting from the current directory. You can also accomplish the same tasks easily in a GUI subversion client such as Tortoise. Just right click the folder and edit the "Properties." Under the subversion tab, you can again, edit properties and select svn:keywords property and add Id to the text field. You can also apply it recursively.

prev 1 2 3 4 next

Products

Goodies

T1EOS

Content Management System T1EOS: Content Management System

Our customized content management framework T1EOS manages articles, blogs, categories, events, tagging, images & galleries, a Facebook Connect integrated commenting system, and more — all out-of-the-box.

github

ASRA

A Simple Restful API

ASRA is a lightweight package that assists in the rapid development of simple APIs for exporting data for Flash, Flex or other applications.

Download

Plum Dumb

A Typeoneerror TextMate Theme Plum Dumb