Pages

Tuesday, February 11, 2014

Copy as HTML plugin in RubyMine

Just a quick note: the Copy as HTML plugin does not show up in the RubyMine 6 plugins listing. But if you download it from here, and install it from disk through the Plugins preferences page, it will work flawlessly in RubyMine. Not sure why it does get listed, but it's a great plugin nonetheless.

Using Teacup to style individual UIView components

I've been doing a bunch of RubyMotion development lately and I'm continually amazed at the power of this framework. One of the many great tools available to RubyMotion developers is Teacup, a UI view layout and styling domain-specific library (DSL). I think DSLs are one of the big advantages that RubyMotion has over traditional native iOS development using Objective-C and Xcode. More information on Teacup here. There's tons of documentation around using Teacup with UIViewControllers, but scant documentation on using Teacup with custom UIView components. There are times that you cannot style a UIView or subclass when the view is initially rendered. Examples include table cells and table headers. Well, don't fear, because you can always mix-in the Teacup layout behavior into any old Ruby class and get that functionality. Below is a table view header helper class that creates new UIView objects with a UILabel subview. Notice how I mix in the Teacup::Layout behavior into the helper and then I have access to all the Teacup stylesheet and layout functionality.

 1 class TableViewHeaderHelper
 2     include Teacup::Layout
 3 
 4     stylesheet :table_view_header
 5 
 6     def create(frame, title)
 7         view = UIView.alloc.initWithFrame(frame)
 8         view.stylename = :root
 9         layout(view) do
10             label = subview(UILabel, :label)
11             label.text = title
12         end
13         view
14     end
15 
16 end

In this above example, the factory method takes a frame and a title for the header. I create the root UIView and then pass that to the Teacup layout to do the rest of the composite magic. Since the title is dynamic, I get a reference to the created UILabel and set the text of the label to the title string passed into the factory method.

Next up is the Teacup stylesheet. This sits in app/styles/styles.rb in my RubyMotion application. I defined a couple of global UIColor objects and then define the table_view_header style for use in the TableViewHeaderHelper class previously shown. The rest of this is standard Teacup functionality, so I won't repeat what they have already documented.

 1 sectionBackgroundColor = UIColor.colorWithRed(221/255.0, 
 2                                               green: 238/255.0, 
 3                                               blue: 249/255.0, 
 4                                               alpha: 1.0)
 5 headerTextColor = UIColor.colorWithRed(50/255.0, 
 6                                        green: 50/255.0, 
 7                                        blue: 50/255.0, 
 8                                        alpha: 1.0)
 9 
10 Teacup::Stylesheet.new :table_view_header do
11 
12     style :root,
13           backgroundColor: sectionBackgroundColor
14 
15     style :label,
16           top: 1, 
17           left: 15, 
18           width: 500, 
19           height: 40,
20           font: :bold.uifont(20),
21           textColor: headerTextColor
22 end

Finally are the UITableViewDelegate protocol methods that I implemented to get a custom header for my UITableView. Note that the frame height used for constructing the UIView in the TableViewHeaderHelper is ignored, and the UITableViewDelegate heightForHeaderInSection:section method is used to determine the header height instead. Kind of strange, but it works.

 1     def tableView(tableView, viewForHeaderInSection: section)
 2         frame = CGRectMake(0, 0, tableView.frame.size.width, 1)
 3         title = "#{@league.name}: My Stations by date"
 4         TableViewHeaderHelper.new.create(frame,
 5                                          title)
 6     end
 7 
 8     def tableView(tableView, heightForHeaderInSection:section)
 9         50
10     end