Git Product home page Git Product logo

reactivecocoalayout's Introduction

ReactiveCocoaLayout

ReactiveCocoaLayout is a framework for describing Cocoa and Cocoa Touch layouts in a reactive way, based on ReactiveCocoa.

This framework is very much a work in progress at the moment, and should be considered alpha quality. Breaking changes may happen often during this time.

Why Not Use Auto Layout?

RCL intends to offer the following advantages over Auto Layout:

  • Explicit and linear layout. Reactive layout proceeds in a linear fashion, making it easier to understand and debug the steps it takes along the way.
  • Top-down layout. A view's layout doesn't interact with its superview's layout unless the former's size or frame is explicitly incorporated in the latter's layout chain, creating a unidirectional relationship that leads to better encapsulation (no global priorities!) and less complexity. Bidirectional relationships are still possible, but must be made explicit.
  • Conditional layouts at runtime. RCL is built on the full power of ReactiveCocoa, and signals can be composed to dynamically disable and re-enable entire layout chains (like when you want to hide and show views) without actually modifying them.
  • Implicit animations. To animate the setting of a view's frame, simply add an animation method into the signal chain. No need to explicitly animate constants anywhere.
  • Incremental use. RCL can be used internally in views without any implementation details leaking out. Callers using Auto Layout or struts and springs can incorporate reactive views without knowing or caring how they perform layout internally. No UI-wide slowdowns or behavior changes just from using RCL!
  • Extensibility. RCL is made up of many independent bits of functionality unified into a framework. It's easy to extend it with your own functionality if you want it to behave differently.
  • Not a black box. Unlike AppKit and UIKit, RCL is an open source project, so you can crack open any particular bit and see why it behaves the way it does.

Getting Started

To start building the framework, clone this repository and then run script/bootstrap. This will automatically pull down any dependencies. Then, simply open ReactiveCocoaLayout.xcworkspace (note: not the .xcodeproj) and build.

To use ReactiveCocoaLayout in your project, you will need to include the ReactiveCocoaLayout.xcodeproj (note: not the .xcworkspace) file in your project, and link ReactiveCocoa and Archimedes into your application target.

License

ReactiveCocoaLayout is released under the MIT license. See LICENSE.md.

reactivecocoalayout's People

Contributors

a2 avatar alanjrogers avatar bigboybad avatar indragiek avatar joshaber avatar joshvera avatar jspahrsummers avatar mdiep avatar robrix avatar yas375 avatar zakdances avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reactivecocoalayout's Issues

Animated signals

<RCLSignal> should offer methods to make a signal "animated." The net result should be that

RAC(self.animatedView.frame) = someAnimatedSignal;

… will result in changes to self.animatedView.frame being animated.

This could perhaps be done by wrapping calls to sendNext: in an animation block, appropriately conditionalized for the platform. The beauty of this approach is that the signal would only send final values while the animation is in flight (like reading from CALayer.modelLayer). One potential drawback is that other signals built on top of it would then become animated themselves, but maybe this is actually an advantage?

Bind to hidden and alpha/alphaValue simultaneously

A binding to rcl_alpha or rcl_alphaValue could automatically flip hidden based on the alpha value.

On iOS, this would mostly just make the hidden property more useful, since there should be no performance difference between alpha = 0 and hidden = YES.

On OS X, however, this would be useful in conjunction with #28. Basically, you could animate the alpha even for a view that's not layer-backed (while resting). rcl_alphaValue could simply translate into hidden, but then a binding could enable layer-backing, animate the alpha, and disable layer-backing once finished.

Declarative layout specifications

Auto Layout does a great job of making layout very declarative. It's hard to beat H:|-[firstView]-(20)-[secondView]-| in terms of expressibility and intent, but we could get close without sacrificing unidirectionality.

For example, maybe something similar to the above could be expressed like:

[self.firstView rcl_maintainIntrinsicContentSize];

RAC(self.firstView.rcl_leading) = [self.rcl_leading plus:8];
RAC(self.secondView.rcl_horizontalFrame) = [[[self.rcl_horizontalFrameSignal
    skipToTrailingOf:self.firstView.rcl_trailing]
    skipLeading:20]
    skipTrailing:8];

If we wanted to take this really far, we could do an ASCII art style specification as well, but that sacrifices some compile-time verifiability.

Why can't I do both alignTop and alignRight?

I'm want to align a UIButton to top-right corner of the super view. When I try something like this

RAC(shareButton,rcl_frame) = [shareButton.rcl_frameSignal alignTop:self.view.rcl_boundsSignal.top];
RAC(shareButton,rcl_frame) = [shareButton.rcl_frameSignal alignRight:self.view.rcl_boundsSignal.right];

it crashes. What am I doing wrong here? What's the proper way to accomplish this?

ResizingWindow throws exceptions if the window is sized too small

Resize the window to the smallest possible height, and you get this exception:

2013-05-14 22:25:00.827 ResizingWindow[81721:303] CALayer bounds contains NaN: [nan nan; 1261 0]
2013-05-14 22:25:00.849 ResizingWindow[81721:303] (
    0   CoreFoundation                      0x00007fff8b0deb06 __exceptionPreprocess + 198
    1   libobjc.A.dylib                     0x00007fff8bb4f3f0 objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8b0de8dc +[NSException raise:format:] + 204
    3   QuartzCore                          0x00007fff8a08d7f7 _ZN2CA5Layer10set_boundsERKNS_4RectEb + 169
    4   QuartzCore                          0x00007fff8a08d6cc -[CALayer setBounds:] + 189
    5   AppKit                              0x00007fff8c7915ff -[_NSViewBackingLayer setBounds:] + 124
    6   AppKit                              0x00007fff8c5e9ae2 -[NSView(NSInternal) _updateLayerGeometryFromView] + 933
    7   AppKit                              0x00007fff8c6b0ad5 -[NSView translateOriginToPoint:] + 188
    8   AppKit                              0x00007fff8c6aef25 -[NSClipView _immediateScrollToPoint:] + 1298
    9   AppKit                              0x00007fff8c6ae963 -[NSClipView scrollToPoint:] + 268
    10  AppKit                              0x00007fff8c6ae710 -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1649
    11  AppKit                              0x00007fff8c6adebd -[NSClipView _reflectDocumentViewFrameChange] + 127
    12  AppKit                              0x00007fff8c5ea143 -[NSView _postFrameChangeNotification] + 216
    13  AppKit                              0x00007fff8c5d4843 -[NSView setFrameSize:] + 1352
    14  AppKit                              0x00007fff8c6a9be6 -[NSTextView(NSPrivate) _setFrameSize:forceScroll:] + 1367
    15  AppKit                              0x00007fff8c6288d8 -[NSTextField setFrameSize:] + 457
    16  AppKit                              0x00007fff8c5d3f8e -[NSView setFrame:] + 299
    17  ReactiveCocoaLayout                 0x00000001000f7b58 -[NSView(RCLGeometryAdditions) setRcl_frame:] + 1096
    18  ReactiveCocoaLayout                 0x00000001000f7683 -[NSView(RCLGeometryAdditions) setRcl_alignmentRect:] + 243
    19  Foundation                          0x00007fff852804f0 _NSSetRectValueForKeyWithMethod + 116
    20  Foundation                          0x00007fff851c87f5 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 408
    21  Foundation                          0x00007fff8522c0bf -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 350
    22  AppKit                              0x00007fff8c57d7fa -[NSView setValue:forKeyPath:] + 392
    23  ReactiveCocoa                       0x000000010003caa1 __45-[RACSignal(Operations) toProperty:onObject:]_block_invoke + 113
    24  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    25  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    26  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    27  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    28  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    29  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    30  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    31  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    32  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    33  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    34  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    35  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    36  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    37  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    38  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    39  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    40  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    41  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    42  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    43  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    44  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    45  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    46  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    47  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    48  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    49  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    50  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    51  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    52  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    53  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    54  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    55  ReactiveCocoa                       0x00000001000354dd __43-[RACSignal(Operations) combineLatestWith:]_block_invoke_2 + 253
    56  ReactiveCocoa                       0x0000000100035caf __43-[RACSignal(Operations) combineLatestWith:]_block_invoke474 + 239
    57  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    58  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    59  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    60  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    61  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    62  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    63  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    64  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    65  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    66  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    67  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    68  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    69  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    70  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    71  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    72  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    73  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    74  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    75  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    76  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    77  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    78  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    79  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    80  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    81  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    82  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    83  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    84  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    85  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    86  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    87  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    88  ReactiveCocoa                       0x00000001000354dd __43-[RACSignal(Operations) combineLatestWith:]_block_invoke_2 + 253
    89  ReactiveCocoa                       0x0000000100035caf __43-[RACSignal(Operations) combineLatestWith:]_block_invoke474 + 239
    90  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    91  ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    92  ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    93  ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    94  ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    95  ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    96  ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    97  ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    98  ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    99  ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    100 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    101 ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    102 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    103 ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    104 ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    105 ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    106 ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    107 ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    108 ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    109 ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    110 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    111 ReactiveCocoa                       0x00000001000354dd __43-[RACSignal(Operations) combineLatestWith:]_block_invoke_2 + 253
    112 ReactiveCocoa                       0x0000000100035caf __43-[RACSignal(Operations) combineLatestWith:]_block_invoke474 + 239
    113 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    114 ReactiveCocoa                       0x0000000100015344 __23-[RACSubject sendNext:]_block_invoke + 84
    115 ReactiveCocoa                       0x00000001000183e0 -[RACSignal performBlockOnEachSubscriber:] + 912
    116 ReactiveCocoa                       0x00000001000152ca -[RACSubject sendNext:] + 154
    117 ReactiveCocoa                       0x0000000100016797 -[RACReplaySubject sendNext:] + 391
    118 ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    119 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    120 ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    121 ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    122 ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    123 ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    124 ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    125 ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    126 ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    127 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    128 ReactiveCocoa                       0x0000000100019df7 __29-[RACSignal(RACStream) bind:]_block_invoke_2156 + 87
    129 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    130 ReactiveCocoa                       0x00000001000189d4 __31+[RACSignal(RACStream) return:]_block_invoke + 84
    131 ReactiveCocoa                       0x000000010001de69 __37-[RACSignal(Subscription) subscribe:]_block_invoke299 + 73
    132 ReactiveCocoa                       0x0000000100062bc0 -[RACSubscriptionScheduler schedule:] + 480
    133 ReactiveCocoa                       0x000000010001d862 -[RACSignal(Subscription) subscribe:] + 1474
    134 ReactiveCocoa                       0x000000010001e99c -[RACSignal(Subscription) subscribeNext:error:completed:] + 1132
    135 ReactiveCocoa                       0x0000000100019c0c __29-[RACSignal(RACStream) bind:]_block_invoke153 + 844
    136 ReactiveCocoa                       0x000000010001a336 __29-[RACSignal(RACStream) bind:]_block_invoke177 + 134
    137 ReactiveCocoa                       0x0000000100011b81 -[RACSubscriber sendNext:] + 289
    138 ReactiveCocoaLayout                 0x00000001000f9a27 __66-[NSNotificationCenter(RACSupport) rac_addObserverForName:object:]_block_invoke_2 + 87
    139 Foundation                          0x00007fff851c3219 -[__NSObserver _doit:] + 322
    140 CoreFoundation                      0x00007fff8b090eda _CFXNotificationPost + 2554
    141 Foundation                          0x00007fff851a8e26 -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
    142 AppKit                              0x00007fff8c5ea16e -[NSView _postFrameChangeNotification] + 259
    143 AppKit                              0x00007fff8c5d4843 -[NSView setFrameSize:] + 1352
    144 AppKit                              0x00007fff8c631003 -[NSWindow _oldPlaceWindow:] + 1605
    145 AppKit                              0x00007fff8c6302e9 -[NSWindow _setFrameCommon:display:stashSize:] + 1837
    146 AppKit                              0x00007fff8cd79a69 -[NSWindow(NSWindowResizing) _resizeWithEvent:] + 1587
    147 AppKit                              0x00007fff8cb7fde9 -[NSTitledFrame mouseDown:] + 189
    148 AppKit                              0x00007fff8cb7d7fe -[NSThemeFrame mouseDown:] + 281
    149 AppKit                              0x00007fff8c6e653e -[NSWindow sendEvent:] + 6853
    150 AppKit                              0x00007fff8c6e2674 -[NSApplication sendEvent:] + 5761
    151 AppKit                              0x00007fff8c5f824a -[NSApplication run] + 636
    152 AppKit                              0x00007fff8c59cc06 NSApplicationMain + 869
    153 ResizingWindow                      0x0000000100001582 main + 34
    154 libdyld.dylib                       0x00007fff839b47e1 start + 0
)

A signal equivalent to AVMakeRectWithAspectRatioInsideRect ?

I've been constructing my own signal to pass a CGSize through AVFoundation's very useful AVMakeRectWithAspectRatioInsideRect function. Example:

self.videoScaledSizeSignal = [[RACSignal combineLatest:@[
    [RACAbleWithStart(self,player.currentItem.tracks) distinctUntilChanged] ,
    [RACAbleWithStart(self.maxSize) distinctUntilChanged]]
    reduce:^(NSArray *array,NSValue *maxSize){

         // If maxSize hasn't been set, just return a zero rect                                   
        CGSize videoScaledSize = CGSizeZero;
        if (CGSizeEqualToSize(maxSize.med_sizeValue, CGSizeZero)) {
                return MEDBox(videoScaledSize);
        }

        for (AVPlayerItemTrack *itemTrack in array) {
                  if ([itemTrack.assetTrack.mediaType isEqualToString:AVMediaTypeVideo]) {

                      CGSize naturalSize = itemTrack.assetTrack.naturalSize;
                      videoScaledSize = AVMakeRectWithAspectRatioInsideRect(naturalSize,  CGRectWithSize(maxSize.med_sizeValue)).size;

                      }

          }


          return MEDBox(videoScaledSize);
      }] filter:^BOOL(NSValue *videoScaledSize) {
            return !CGSizeEqualToSize(videoScaledSize.med_sizeValue, CGSizeZero);
   }];

I was going to submit a pull request for a RACSignal category containing a simplified version of my above signal, but there's a problem. AVMakeRectWithAspectRatioInsideRect requires AVFoundation, and I'm not sure it's a good idea to add a big dependency like that to RCL.

What would the best way be to add this functionality to RCL (or RAC)?

Equally Space Views

What's the easiest way to equally space views with RCL? Would I just align each view’s left side to the previous view’s right side?

Integralization

Could be done through a RCL() macro (similar to the RAC macro) which makes frames integral as they arrive:

RCL(self.view.frame) = possiblyMisalignedRectSignal;
RCL(self.otherView.frame) = [possiblyMisalignedRectSignal insetWidth:10 height:25.5];

If rects should be integralized for other calculations, it could be done through an -integral method on <RCLSignal>.

In either case, functionality should be similar to Archimedes' CGRectFloor, and preserve desired sizes.

(NS | UI)EdgeInsets operators

Related: github/Archimedes#17

Currently, RACSignal+RCLGeometryAdditions.h has -insetWidth:height: which isn't too useful for applying insets where top/bottom and left/right aren't equal. I propose a new operator, -inset: which accepts a signal that sends boxed NSEdgeInsets or UIEdgeInsets values and applies them to a CGRect.

I would be happy to implement this. Any thoughts?

Where is rcl_center?

The 2 most frequent layout attributes I manipulate are bounds and center. RCL has a beautiful rcl_bounds which I use to set bounds, but where is the equivalent for center? The closest thing I can find is rcl_frameSignal.center which is a read-only signal. Where is rcl_center?

Why can't I use signals that return constant numbers in my layout chain?

Everytime I try, it crashes. Example:

RAC(self.playButton,rcl_frame) = [[self.playButton.rcl_frameSignal 
    alignCenterX:self.playButton.superview.rcl_boundsSignal.centerX]
    replaceY:[RACSignal return:@0]];

I want to pass 0 to replaceY but all I get is a crash. Is there some other way to pass simple, constant numbers to RCL?

ld: library not found for -lReactiveCocoaLayout iOS

Trying to add ReactiveCocoaLayout to my workspace for an iOS project with no luck. I've added the xcodeproj file itself to my project navigator and I've also added ReactiveCocoaLayout iOS to the Link Binary with Libraries tab of my main project's target. Why am I getting this error?

ld: library not found for -lReactiveCocoaLayout iOS
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Ld /Users/zak/Library/Developer/Xcode/DerivedData/MyProject-gnimssqlbcaoovceuojorxxwmhlo/Build/Products/Debug-iphonesimulator/MyProject.app/MyProject normal i386
cd /Users/zak/projects/MyProject/XCode
setenv IPHONEOS_DEPLOYMENT_TARGET 6.1
setenv PATH "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:/opt/local/bin:/usr/local/git/bin"
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk -L/Users/zak/Library/Developer/Xcode/DerivedData/MyProject-gnimssqlbcaoovceuojorxxwmhlo/Build/Products/Debug-iphonesimulator -F/Users/zak/Library/Developer/Xcode/DerivedData/MyProject-gnimssqlbcawovceuojorxxwmhlo/Build/Products/Debug-iphonesimulator -filelist /Users/zak/Library/Developer/Xcode/DerivedData/MyProject-gnimssqlbcawovceuojorxxwmhlo/Build/Intermediates/MyProject.build/Debug-iphonesimulator/MyProject.build/Objects-normal/i386/MyProject.LinkFileList -Xlinker -objc_abi_version -Xlinker 2 -ObjC -lsqlite3.0 -framework CoreData -framework CoreLocation -framework CoreText -framework Foundation -framework MobileCoreServices -framework QuartzCore -framework SystemConfiguration -weak_framework Accounts -weak_framework AdSupport -weak_framework Social -all_load -fobjc-arc -fobjc-link-runtime -Xlinker -no_implicit_dylibs -mios-simulator-version-min=6.1 "-lReactiveCocoaLayout iOS" -framework CoreText -framework AVFoundation -framework AssetsLibrary -framework AudioToolbox -framework OpenAL -framework CoreMedia -framework Foundation -framework Twitter -framework MediaPlayer -framework QuartzCore -framework Security -framework MobileCoreServices -framework SystemConfiguration -framework UIKit -framework CoreGraphics -lPods -o /Users/zak/Library/Developer/Xcode/DerivedData/MyProject-gnimssqlbcawovceuojorxxwmhlo/Build/Products/Debug-iphonesimulator/MyProject.app/MyProject

Use NSLayoutAttribute instead of CGRectEdge values for geometry

This would lead to a more consistent and flexible API.

As part of this, all methods currently accepting a signal of edges should be changed to accept a constant NSLayoutAttribute, since 80% of the time there should be no reason to change the attribute that your layout occurs relative to (and the pain of boxing it in a signal isn't worth it for the 20%).

CGRectInset() returning NaN values

When using any operator that uses CGRectInset() internally (e.g. -insetWidth:height:), if the rect being inset is too small to apply the inset, CGRectInset() will return a rect with some values set to NaN. This is especially dangerous when binding to rcl_frame or rcl_bounds as NSView throws an exception when attempting to set a frame with non-finite values.

What would be a good solution for this? One way is to just not use CGRectInset() and apply the insets manually (yielding negative values for some members, which won't throw an exception) or keep CGRectInset() and check for NaN values afterwards, replacing them with 0's or something suitable.

Automatically derive intrinsic content size

This is only a half-baked idea, but it would be cool if a view's implementation of -instrinicContentSize could somehow use the same signal chain that the view uses for laying out its subviews.

It seems like this would involve some sort of redirection, so that:

  • Live inputs – like self.rcl_boundsSignal – are zeroed out or somehow mocked, to ensure that they don't factor into the size calculations.
  • Output bindings – e.g., RAC(self.subview.frame) – are disabled, so no layout is actually performed.

Create New Tag

I'm using this in an open source project but I've got an open source issue where RCL is failing to compile: TeehanLax/Upcoming#161 Admittedly, this is when using CocoaPods instead of a submodule, which would fix the problem with a git submodule update. 0.3.2 was tagged months ago, and I can't update the pod spec without a new tag.

I just need a tag created after this commit: 4a76a40#diff-2507d6d10b3a2c6684ac682ff9ba4ef5 . Then I can update the CocoaPods pod spec for RCL.

when I set rcl_top , why the height and width changed ?

I write code as below :

self.ivIcon=[[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 80, 80)];
[self.view addSubview:self.ivIcon];
self.lblTitle=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 12)];
[self.view addSubview:self.lblTitle];
RCLAlignment(self.lblTitle)=@{
                              rcl_top: self.ivIcon.rcl_frameSignal.top,
                              };

I get the self.lblTitle frame = (0 20; 60 18). I don't know why the Height and Width changed. Could you tell me the reason. I am newer to ReactiveCocoa and The Framework. I try to debug find the reason. But I find It's so hard to find a useful information about it .
And what's the difference between RCLAlignment and RCLFrame. I can't understand it.
Hope your anwer, thanks

Support key frame animations

It'd be nice if there were first-class support for key frame animations. I'm not totally sure what that would look like. Maybe an operator like -sequenceNext: but that completes when the animation completes? It'd be kinda dumb-guy keyframing but it'd work.

Concat after animation

Similar to #53

Suppose I have something like:

RAC(self.view.rcl_frame) = [[[RACSignal return:startingRect] concat:animatedPresentation] concat:resizeAsNeeded];

The problem is that the final concat:resizeAsNeeded will be concatted immediately, which wipes out the animation, instead of being concatted after the animated signal's animation completes.

I suppose I want something like -concatAfterAnimation:. But this also makes me wonder about subclassing RACSignal to make a RCLAnimatedSignal which overrides -concat:.

RCL doesn't respect `flipped` coordinate space?

I have a window that has a contentView with a flipped coordinate space in OSX. I do something like this:

RCLFrame(subHeader) = @{rcl_rect: subHeader.rcl_frameSignal,
                      rcl_top: [RACSignal return:@(100)]};

and the y coordinate of "subHeader" ends up as -100. Is this intended behavior? Is it recommended to avoid flipping the coordinate space of parent views?

edit Looks like something else is going on. I tried a value of -50 for rcl_top and the y gets set at -250. Why?

Adopt the Flexbox spec. It's been much improved over the past year.

This recommendation will require some pretty major additions/changes to RCL, so it's kinda "big picture" but I really think its worth considering so here I go...

For those of you who don't know what Flexbox is, here's a quick overview:

Flexbox is a new CSS3 layout module that's gone through a few revisions, but has now achieved relatively wide browser support. The latest 2012 revision (published by the W3) is here. Google offers even more info.

I've been playing around with Flexbox for a few years now. It's evolved quickly, and it's now at the point where it's become an essential part of my web toolkit. It truly is fantastic...it solves so many layout-related issues and features an easy to remember syntax.

Basically it breaks your layout into "boxes", then provides you with a ton of options for pivoting and sizing of those boxes, including being able to size based on not only pixels and percentages, but proportions to other flexboxes.

As an example, I'm going to use this recently filed issue and solve it with flexbox. Say you want to equally space 3 views inside of a parent view:

<div class="parent">
   <div class="child-a"></div>
   <div class="child-b"></div>
   <div class="child-c"></div>
</div>

now the CSS:

.parent {
   width: 800px;
   height: 200px;
   display: flex;
}
.child-a, .child-b, .child-c {
   flex: auto;
}

And that's it. Equally sized children based on parent size (which doesn't have to be static) without having to mess with weird 33% percentages.

I know that it's web tech right now (now objective c) but I really feel the Flexbox designers have done great work that can help other designers. It's worth reading over the spec. Having a cross-platform layout standard would be super cool.

I'm gonna have to think a bit more what a flexbox-liked syntax would look like in RCL/objective-c, so maybe this issue can be closed and the content moved to a working document in the RCL wiki.

Thoughts?

Automatically enable layer-backing during an animation

Animations are noticeably smoother when a view is layer-backed.

RCL could automatically enable layer-backing on NSViews when any property managed by the framework (like rcl_frame) is animated as part of a signal chain, and then disable layer-backing for all such views once the animation completes.

Split animation behaviors into a separate library

RCL's animations are super amazing, but not well-known at all, and the rest of the framework scares off folks who might otherwise use them.

It's also just poor modularity: the animation and layout APIs don't really have any dependency on one another, so why should they be part of the same library?

I think we should spin that stuff off into a separate “ReactiveAnimation” framework or something.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.