A script to convert Visual Formatting Language into native Objective C code for iOS developers
vfl2objc
is a tool to convert VFL (Visual Formatting Language) based UI layout to native, frame-based, Objective-C code.
sudo setup.rb
This will copy the necessary files to the necessary folders to integrate nicely with Xcode.
Fist, restart Xcode, then navigate to Xcode > Services
in the upper left application menu. You should be able to see the vfl-file service listed under the General section.
To start a new VFL based code block, enter something like below in the right place in your code:
UIView* superview = someView;
// begin VFL
/*
|-10-[someElement]-10-|
V:|-5-[someElement(100)]
*/
// end VFL
Note: the first line and the last line are important. The final // end VFL
must be followed by a LF line break (\n
). You can also // VFL begin
and // VFL end
vfl-file
serviceMake sure you save the file (Cmd+S), then navigate to Xcode > Services > vfl-file
in the upper left application menu. The VFL block you entered will expand to a full code block!
Each time after editing something in the VFL section, also press Cmd+S and run the vfl-file service, so the code will get updated.
Protip: you can add a keyboard shortcut to the vfl-file menu in System Preferences > Keyboard > Keyboard Shortcuts
|-5-[A(100)]
This means that element A is 5 points from the left edge of its container, and it’s 100 points wide. And A has flexible right margin.
V:|-10-[B(50)]
This means that element B is 10 points from the top edge and is 50 points tall. (V means vertical). And B has flexible bottom margin.
|-5-[C]-5-|
This means that C has flexible width, and it’s 5 points to the left edge and 5 points to the right edge.
V:[D]|
This means that D is touching the bottom edge, and have a flexible top margin, and D’s height should be set beyond the VFL based block (either before or after)
|-5-[E]-5-[F(50)]-5-[G(>0)]-5-|
This means that E has a fixed width set outside the VFL block, F has a fixed width of 50 points, G has a flexible width
[H(100)]
This means that H is 100 points wide. However it’s position and autoresizing mask is unknown, so you need to set them beyond the VFL block.
The rule of thumb is that there can be 1 and only 1 flexible element in each dimension:
|-5-[A(100)]-5-|
This is wrong because when the superview width is not 110 there will be a conflict.
|-5-[A(>0)]-5-[B(>0)]-5-|
This is wrong because it is an ambiguous layout—it is unclear on how to assign the widths for A and B.
Variables and constants can be used to replace the numbers:
|-margin-[button(width)]
Everything else follows Apple’s official VFL documentation, with one exception: vlf2objc
supports center
before brackets.
center[A(200)]
This means A’s width is 200 and A is horizontally centered in its superview.
V:center[B(100)]
This means B’s height is 100 and B is vertically centered in its superview.
Unlike Cocoa Autolayout, vfl2objc
allows you to override the frame of an element before or after the generated code block.
For example this is valid allowed:
labelA.text = @"hi";
[labelA sizeToFit];
// generated code based on |-[labelA]-10-[itemB]
This is also valid and allowed:
// generated code based on [itemX(100)]
UpdateWidthBasedOnSomeLogic(itemX); // this keeps the x, y, height set in the VFL block and just updates the width
However, the following example will not work:
// generated code based on |[itemX]-[itemY(100)]
[itemX setWidth:100];
itemY
’s position depends on itemX
’s frame, so itemX
’s setWidth
call must go before the generated code block.
You can use this script to convert raw VFL to Objective-C code from command line:
echo "|-10-[button]
V:[button]-|" | vfl2objc.rb --raw
Or convert an Objective-C source code file, preserving non-VFL areas. To do so, run either:
cat yourfile.m | vfl2objc.rb > yourfile_with_changes.m
Or transform it in place:
vfl2objc.rb -f yourfile.m
Other than manually triggering the script with Mac Service, you can consider to integrate VFL code generation into pre-build script.
To do this:
In Xcode Toolbar, choose your scheme and edit your scheme.
Protip: If you use git, you may want to go to “manage scheme” and make your scheme “shared” first, so the scheme config will be in your git repo.
Inside scheme editor, expand “Build”, and add a pre-action
Use whatever scripting language to create a script that loops through all your .m
files, and call vfl2objc.rb -f {file_path}
Copyright © 2013 by Hulu, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.