PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/MGBox2-master/README.markdown

https://gitlab.com/praveenvelanati/ios-demo
Markdown | 476 lines | 316 code | 160 blank | 0 comment | 0 complexity | 50264da21afca64f23b4fd0ef5274b7f MD5 | raw file
  1. # MGBox2 - Simple, quick iOS tables, grids, and more
  2. Designed for rapid table and grid creation with minimal code, easy customisation, attractive default styling, using modern blocks based design patterns, and without need for fidgety tweaking or awkward design patterns.
  3. Includes blocks based gesture recognisers, observers, control events, and custom events.
  4. `MGBox`, `MGScrollView`, and `MGButton` can also be used as generic `UIView` wrappers to get the benefits of view padding, margins, and zIndex, amongst others.
  5. ## Layout Features
  6. - Table layouts (similar to `UITableView`, but less fuss)
  7. - Grid layouts (similar to `UICollectionView`, but less fuss)
  8. - Table rows automatically layout `NSStrings`, `UIImages`,
  9. `NSAttributedStrings`, and multiline text
  10. - Table rows accept `Mush` lightweight markup for bold, italics, underline, and
  11. monospace
  12. - Animated adding/removing/reordering rows, boxes, sections, etc
  13. - CSS-like `margin`, `padding`, `zIndex`, `fixedPosition`, and more
  14. - Separate top/right/bottom/left borders, and optional etched border style
  15. - Optional asynchronous blocks based layout
  16. - Automatically keeps input fields above the keyboard
  17. - Optional scroll view box edge snapping
  18. ## Code Convenience Features
  19. - Blocks based tap, swipe, and hold gesture recognisers
  20. - Blocks based custom event observing and triggering
  21. - Blocks based UIControl event handlers
  22. - Blocks based keypath observers
  23. - UIView easy frame accessors
  24. ## Example Screenshots
  25. Complex tables, sections, and grids created with simple code.
  26. ### From the Demo App
  27. ![Demo App Screenshot](http://cloud.github.com/downloads/sobri909/MGBox2/DemoApp6.png)
  28. ### From [IfAlarm](http://ifalarm.com)
  29. Created with the convenience `-[MGBox screenshot:]` method.
  30. ![IfAlarm Screenshot 1](http://cloud.github.com/downloads/sobri909/MGBox2/IfAlarm1.png)
  31. ![IfAlarm Screenshot 2](http://cloud.github.com/downloads/sobri909/MGBox2/IfAlarm2.png)
  32. ### From [Flowies](http://flowi.es)
  33. ![Flowies Screenshot 1](http://cloud.github.com/downloads/sobri909/MGBox2/Flowies1.png)
  34. ## Setup
  35. 1. Add the `MGBox` folder to your project. (ARC and Xcode 4.5 are required)
  36. 2. Add the `CoreText` and `QuartzCore` frameworks to your project.
  37. Have a poke around the Demo App to see some of the features in use.
  38. ## Example Usage
  39. ### Building a Table (Similar to UITableView)
  40. #### Create a Scroll View:
  41. ```objc
  42. MGScrollView *scroller = [MGScrollView scrollerWithSize:self.bounds.size];
  43. [self.view addSubview:scroller];
  44. ```
  45. #### Add a Table Section:
  46. ```
  47. MGTableBoxStyled *section = MGTableBoxStyled.box;
  48. [scroller.boxes addObject:section];
  49. ```
  50. #### Add Some Rows:
  51. ```objc
  52. // a default row size
  53. CGSize rowSize = (CGSize){304, 40};
  54. // a header row
  55. MGLineStyled *header = [MGLineStyled lineWithLeft:@"My First Table" right:nil size:rowSize];
  56. header.leftPadding = header.rightPadding = 16;
  57. [section.topLines addObject:header];
  58. // a string on the left and a horse on the right
  59. MGLineStyled *row1 = [MGLineStyled lineWithLeft:@"Left text"
  60. right:[UIImage imageNamed:@"horse.png"] size:rowSize];
  61. [section.topLines addObject:row1];
  62. // a string with Mush markup
  63. MGLineStyled *row2 = MGLineStyled.line;
  64. row2.multilineLeft = @"This row has **bold** text, //italics// text, __underlined__ text, "
  65. "and some `monospaced` text. The text will span more than one line, and the row will "
  66. "automatically adjust its height to fit.|mush";
  67. row2.minHeight = 40;
  68. [section.topLines addObject:row2];
  69. ```
  70. #### Animate and Scroll the Section Into View
  71. ```objc
  72. [scroller layoutWithSpeed:0.3 completion:nil];
  73. [scroller scrollToView:section withMargin:8];
  74. ```
  75. ### Build a Grid (Similar to UICollectionView or CSS's float:left)
  76. #### Create the Grid Container:
  77. ```objc
  78. MGBox *grid = [MGBox boxWithSize:self.bounds.size];
  79. grid.contentLayoutMode = MGLayoutGridStyle;
  80. [scroller.boxes addObject:grid];
  81. ```
  82. #### Add Some Views to the Grid:
  83. ```objc
  84. // add ten 100x100 boxes, with 10pt top and left margins
  85. for (int i = 0; i < 10; i++) {
  86. MGBox *box = [MGBox boxWithSize:(CGSize){100, 100}];
  87. box.leftMargin = box.topMargin = 10;
  88. [grid.boxes addObject:box];
  89. }
  90. ```
  91. #### Animate and Scroll the Grid Into View:
  92. ```objc
  93. [grid layoutWithSpeed:0.3 completion:nil];
  94. [scroller layoutWithSpeed:0.3 completion:nil];
  95. [scroller scrollToView:grid withMargin:10];
  96. ```
  97. ## Animated and Asynchronous Layout
  98. All `MGBoxes`, `MGScrollViews`, and subclasses support two layout methods (`layout`, `layoutWithSpeed:completion:`) and two async layout block properties (`asyncLayout` and `asyncLayoutOnce`).
  99. ### [box layout]
  100. Layout the box's children (and all descendents) without animation.
  101. ### [box layoutWithSpeed:completion:]
  102. Same as above, but with child boxes animated between previous and new computed positions, fading new boxes in, and fading removed boxes out. Child boxes will have their unanimated `layout` method called. If you want a child box to also animate the positioning of its children in the same drawing pass, call its `layoutWithSpeed:completion:` method first.
  103. ```objc
  104. [grid layoutWithSpeed:0.3 completion:nil];
  105. [scroller layoutWithSpeed:0.3 completion:nil];
  106. ```
  107. ### box.asyncLayout and box.asyncLayoutOnce
  108. `asyncLayout` blocks are performed on every call to `layout` or `layoutWithSpeed:completion:`.
  109. ```objc
  110. box.asyncLayout = ^{
  111. // do slow things on a background thread
  112. NSLog(@"things things things");
  113. // update the box presentation back in UI land
  114. dispatch_async(dispatch_get_main_queue(), ^{
  115. NSLog(@"that took a while!");
  116. });
  117. };
  118. ```
  119. `asyncLayoutOnce` blocks are performed only on the first call to `layout` or `layoutWithSpeed:completion:`, thus are useful for initial table or grid setup, when things like loading data over the network might be a performance factor.
  120. ```objc
  121. box.asyncLayoutOnce = ^{
  122. // do slow things once, on a background thread
  123. NSLog(@"things things things");
  124. // update the box presentation back in UI land
  125. dispatch_async(dispatch_get_main_queue(), ^{
  126. NSLog(@"aaand we're done");
  127. });
  128. };
  129. ```
  130. Assign a specific queue to the `asyncQueue` property if you want to use a different priority or perhaps perform a bunch of expensive processes in serial.
  131. ```objc
  132. dispatch_queue_t queue = dispatch_queue_create("SerialQueue", DISPATCH_QUEUE_SERIAL);
  133. for (MGBox *box in scroller.boxes) {
  134. box.asyncQueue = queue;
  135. }
  136. ```
  137. ## MGBox's CSS-like Positioning and Stacking
  138. ### Margins and Padding
  139. When `layout` or `layoutWithSpeed:completion:` is called, each descendent box in the tree is positioned according to the container box's `contentLayoutMode` (ie table or grid), taking into account the container's padding and the child's margins.
  140. Getters and setters are provided for:
  141. * `padding` (`UIEdgeInsets`)
  142. * `margin` (`UIEdgeInsets`)
  143. * `leftPadding`, `topPadding`, `rightPadding`, `bottomPadding`
  144. * `leftMargin`, `topMargin`, `rightMargin`, `bottomMargin`
  145. ### Z-Index
  146. The same as in CSS. The `zIndex` property of `MGBox` affects the stacking order of boxes during layout.
  147. ### Fixed Positioning
  148. Set a box's `fixedPosition` property to a desired `CGPoint` to force it to stay in a fixed position when its containing `MGScrollView` scrolls.
  149. ### Attached Positioning
  150. Assign another view to a box's `attachedTo` property to force the box to position at the same origin. Optionally adjust the offset by fiddling with the box's top and left margins.
  151. ## MGBox Borders
  152. `MGBox` provides setters for individual top/right/bottom/left border colours, as well as a built in etched border style.
  153. Set border colours individually with `topBorderColor`, etc. Set all border colours in one go with `borderColors`, like thus:
  154. ```objc
  155. MGBox *box = MGBox.box;
  156. // all borders the same colour
  157. box.borderColors = UIColor.redColor;
  158. // individual colours (order is top, left, bottom, right)
  159. box.borderColors = @[
  160. UIColor.redColor, UIColor.greenColor,
  161. UIColor.blueColor, UIColor.blackColor
  162. ];
  163. ```
  164. The `borderStyle` property provides etched borders. Like thus:
  165. ```objc
  166. // just top and bottom etches (as you'd see in a table row)
  167. box.borderStyle = MGBorderEtchedTop | MGBorderEtchedBottom;
  168. // borders on all sides except left
  169. box.borderStyle = MGBorderEtchedAll & ~MGBorderEtchedLeft;
  170. // no borders
  171. box.borderStyle = MGBorderNone;
  172. ```
  173. ## Blocks Based Observers, Custom Events, Control Events, and Gestures
  174. ### Tap, Swipe, and Hold
  175. Simply assign a block to the appropriate property. You can toggle them on and off with `tappable`, `swipable`, `longPressable` booleans. Access the gesture recognisers directly through the `tapper`, `swiper`, and `longPresser` properties.
  176. ```objc
  177. box.onTap = ^{
  178. NSLog(@"you tapped my box!");
  179. };
  180. box.onSwipe = ^{
  181. NSLog(@"you swiped, m'lord?");
  182. };
  183. box.onLongPress = ^{
  184. NSLog(@"you can let go now.");
  185. };
  186. ```
  187. ### Blocks Based Observers
  188. `NSObject+MGEvents` provides blocks based observing for all objects' keypaths. No more worrying about crashes caused by dangling observers after dealloc.
  189. ```objc
  190. [earth onChangeOf:@"isFlat" do:^{
  191. if (earth.isFlat) {
  192. NSLog(@"the earth is now flat");
  193. } else {
  194. NSLog(@"the earth is no longer flat.");
  195. }
  196. }];
  197. ```
  198. ### Blocks Based Custom Events
  199. `NSObject+MGEvents` provides the ability to define custom events, assign block handlers, and trigger the events when you see fit.
  200. ```objc
  201. [earth on:@"ChangingShape" do:^{
  202. NSLog(@"the earth is changing shape");
  203. }];
  204. [earth trigger:@"ChangingShape"];
  205. ```
  206. ### Blocks Based UIControl Event Handlers
  207. `UIControl+MGEvents` provides a nice easy `onControlEvent:do:` method for all UIControls, which frees you from the muck of adding targets, selectors, etc.
  208. ```objc
  209. [button onControlEvent:UIControlEventTouchUpInside do:^{
  210. NSLog(@"i've been touched up inside. golly.");
  211. }];
  212. ```
  213. ## UIView+MGEasyFrame Category
  214. Fussing about with view frames can be tedious, especially when all you want to do is change a width or height, or know where the bottom right corner is.
  215. `UIView+MGEasyFrame` provides getters and setters for:
  216. * `size`, `width`, `height`
  217. * `origin`, `x`, `y`
  218. And getters for:
  219. * `topLeft`, `topRight`, `bottomRight`, `bottomLeft`
  220. ## Subclassing Tips
  221. While `MGLine` and `MGScrollView` rarely need subclassing, it's often useful to subclass `MGBox` when building things like items in a grid container, or for any generic views that you might want to layout using `MGBox` style layout rules (eg margins, zIndex, etc).
  222. Also, if you want to create a custom table section style, you'll want to subclass `MGTableBox`, looking at `MGTableBoxStyled` as an example.
  223. All `MGBoxes` have a convenience `setup` method which is called from both `initWithFrame:` and `initWithCoder:`, thus making it a good location to apply any custom styling such as shadows, background colours, corner radiuses, etc. You should probably call `[super setup]` in here.
  224. Additionally you might want to override the standard `layout` method, if you want to perform some tasks before or after layout. You should almost certainly call `[super layout]` in your custom layout method.
  225. If your custom `MGBox` has a shadow, it's useful to adjust its `shadowPath` in the `layout` method, after `[super layout]`, because shadows without shadowPaths make iOS cry.
  226. ## The Difference Between 'boxes' and 'subviews'
  227. This distinction can present an occasional trap. When `layout` or `layoutWithSpeed:completion:` are called, the layout engine only applies `MGBox` layout rules to boxes in the container's `boxes` set. All other views in `subviews` will simply be ignored, with no `MGBox` style layout rules applied (their `zIndex` will be treated as `0`).
  228. All `MGBoxes` that are subviews but are not in `boxes` will be removed during layout. Any `MGBoxes` in `boxes` that are not yet subviews will be added as subviews.
  229. So as a general rule of thumb: Put `MGBoxes` into `boxes`, everything else into `subviews`, then call one of the `layout` methods when you're done. As long as you stick to that, you won't get tripped up.
  230. ## MGLine
  231. `MGLine` is essentially a table row, although it can also be used more generically if it takes your fancy.
  232. Although `MGLine` is an `MGBox` subclass, it instead sources its content views from `leftItems`, `middleItems`, and `rightItems`.
  233. The items arrays can contain `NSStrings`, `UIImages`, or any arbitrary `UIViews` you want to add to the line (eg switches, sliders, buttons, etc).
  234. ### MGLine Multiline Text
  235. `MGLine` can automatically wrap long strings, as well as mix and match them with other items in the same line. For example you might want multiline text on the left and an image on the right, or vice versa.
  236. ```objc
  237. MGLine *line1 = [MGLine lineWithMultilineLeft:@"a long string on the left"
  238. right:[UIImage imageNamed:@"Sharonda"] width:320 minHeight:40];
  239. MGLine *line2 = [MGLine lineWithleft:[UIImage imageNamed:@"Felicia"
  240. multilineRight:@"a long string on the right" width:320 minHeight:40];
  241. ```
  242. Any string containing a newline char will be treated as multiline, so as a shorthand you can also do something like this:
  243. ```objc
  244. MGLine *line = [MGLine lineWithLeft:@"a long string\n" right:nil];
  245. ```
  246. ### MGLine Mush Text Markup and Attributed Strings
  247. `MGLine` can automatically parse Mush markup into bold, italics, underlined, and monospaced attributed strings. It will also accept any given `NSAttributedString`. Append "|mush" to any string to pass to `MGLine` to indicate that you want it parsed.
  248. ```objc
  249. MGLineStyled *line1 = MGLineStyled.line;
  250. line1.font = [UIFont fontWithName:@"HelveticaNeue" size:16];
  251. line1.leftItems = (id)@"**Some bold on the left**|mush";
  252. line1.rightItems = (id)@"//Some italics on the right//|mush";
  253. MGLineStyled *line2 = MGLineStyled.line;
  254. line2.font = [UIFont fontWithName:@"HelveticaNeue" size:16];
  255. line2.multilineLeft = @"Pretend this is a //very long string//, and pretend it "
  256. "has some reason to include `some monospaced text`.|mush";
  257. line2.minHeight = 40;
  258. ```
  259. Note that iOS 6 is required to use `NSAttributedString` in a `UILabel`, so `MGLine` will fall back to presenting plain old strings on iOS 5 devices (with the markup stripped out).
  260. ### MGLine Side Precedence
  261. The `sidePrecedence` property decides whether content on the left, right, or middle takes precedence when space runs out. `UILabels` will be shortened to fit. `UIImages` and `UIViews` will be removed from the centre outwards if there's not enough room to fit them in.
  262. ### MGLine Fonts, Text Colours, Text Shadows, and Text Alignment
  263. The `font`, `middleFont`, and `rightFont` properties define what fonts are used to wrap `NSStrings`. If no right or middle font is set, the main `font` value is used.
  264. The `textColor`, `middleTextColor`, and `rightTextColor` properties are fairly self explanatory. Again, if a right or middle colour isn't set, the main `textColor` value is used.
  265. The `textShadowColor`, `middleTextShadowColor`, and `rightTextShadowColor` properties follow the trend.
  266. The `leftTextShadowOffset`, `middleTextShadowOffset`, `rightTextShadowOffset` properties define text shadow offsets. They all default to {0, 1}.
  267. The properties `leftItemsTextAlignment`, `middleItemsTextAlignment`, `rightItemsTextAlignment` are passed on to the labels created for your strings.
  268. ### MGLine Item Padding
  269. The `itemPadding` property defines how much padding to apply to the left and right of each item. This is added to the `leftMargin` and `rightMargin` values of any `MGBoxes` you might have added as line items.
  270. ### MGLine Min and Max Height
  271. By default the `minHeight` and `maxHeight` properties are both zero, thus causing the line's size to be unchanged by the size of its contents. But if either of them is non-zero, the line height will adjust to fit the highest content item, within the given bounds.
  272. A `maxHeight` of zero when `minHeight` is non-zero allows the line to increase in height without restriction.
  273. ```objc
  274. MGLine *line = [MGLine lineWithLeft:@"a really long string\n" right:nil];
  275. line.minHeight = 40; // the line will be at least 40 high
  276. line.maxHeight = 0; // the line will grow as high as it needs to accommodate the string
  277. ```
  278. ## MGTableBox, MGTableBoxStyled
  279. `MGTableBox` is a thin wrapper of `MGBox` which you can mostly pretend doesn't exist, unless you want to create a custom table section style. In which case you will want to subclass it.
  280. `MGTableBoxStyled` is a styled subclass of `MGTableBox`, which provides the default table style you see in the screenshots and demo app.
  281. When using these classes for table sections, add your rows (eg `MGLine` objects) to their `topLines`, `middleLines`, and `bottomLines` arrays (instead of the standard `boxes` set).
  282. ## MGScrollView
  283. ### MGScrollView Input Fields Above Keyboard
  284. `MGScrollViews` will by default automatically scroll to keep any selected input field visible when the keyboard appears. You can adjust the amount of margin with the `keyboardMargin` property, and disable the feature with the `keepFirstResponderAboveKeyboard` property.
  285. ### MGScrollView Box Edge Snapping
  286. You might like this for your project, or it might annoy you. It's one of those things.
  287. ### When You Make the Scroll View:
  288. ```objc
  289. scroller.delegate = self;
  290. ```
  291. ### In Your ViewController.h:
  292. Own up to being a `UIScrollViewDelegate`
  293. ```objc
  294. @interface ViewController : UIViewController <UIScollViewDelegate>
  295. ```
  296. ### In Your ViewController.m:
  297. ```objc
  298. - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
  299. [(id)scrollView snapToNearestBox];
  300. }
  301. - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
  302. willDecelerate:(BOOL)decelerate {
  303. if (!decelerate) {
  304. [(id)scrollView snapToNearestBox];
  305. }
  306. }
  307. ```
  308. ## Take a Screenshot of Your Box (with OS X screenshot style drop shadow)
  309. ```objc
  310. UIImage *screenshot = [box screenshot:0]; // 0 = device scale, 1 = old school, 2 = retina
  311. ```
  312. ## License
  313. No need to give credit or mention `MGBox` in your app. No one reads those things anyway. The license is otherwise BSD standard.
  314. If you want to give back, you could always [buy one of my apps](http://bigpaua.com) ;)
  315. ## More
  316. There's a few more undocumented features, if you're the type to go poking around the source. Enjoy!