GithubHelp home page GithubHelp logo

bryankeller / blkflexibleheightbar Goto Github PK

View Code? Open in Web Editor NEW
3.0K 90.0 338.0 148 KB

Create condensing header bars like those seen in the Facebook, Square Cash, and Safari iOS apps.

License: MIT License

Objective-C 99.15% Ruby 0.85%

blkflexibleheightbar's Introduction

BLKFlexibleHeightBar

Create condensing header bars like those seen in the Facebook, Square Cash, and Safari iOS apps.

Square Cash Style Bar

Square Cash Style Bar

BLKFlexibleHeightBar allows you to create header bars with flexible heights. Often, this sort of UI paradigm is used to hide "chrome" and make room for more content as a user is scrolling. This is seen in third party apps like Facebook and Square Cash, as well as first party apps like Safari.

BLKFlexibleHeightBar can create bars that look and act any way you'd like:

  • Immediate subviews of a flexible height bar define how they want to look and where they want to be depending on the height of the bar. Properties like frame, transform, and alpha can all vary depending on the current height of the bar.
  • A bar's behavior can be defined using a behavior definer instance. A behavior definer can be created to emulate Safari's header behavior, Facebook's header behavior, or something entirely new. Behaviors are completely modular and aren't coupled with the appearence of the bar.

Due to this library's modular, extensible nature, you are not limited to any one look or any one feel. What UICollectionView does for presenting collections of data, BLKFlexibleHeightBar does for creating header bars.

How do I install it?

CocoaPods Installation

  1. Add pod 'BLKFlexibleHeightBar' to your project's Podfile.
  2. Run pod install.

Manual Installation

  1. Clone this repo or click "Download ZIP" on the side.
  2. Copy all of the files in the "BLKFlexibleHeightBar" folder into your project. You probably want to check the box that says "Copy items if needed" as well as make sure that the target you want to add the files to is checked.

How do I use it?

###Before we get started, understand this: The height of the bar is not set directy by adjusting the bar's frame. Rather, height adjustments are made by setting the progress property of the bar. The progress property represents how much the bar has shrunk from its maximum height to its minimum height

  • progress == 0.0 means the bar is at its maximum height.
  • progress == 0.5 means the bar is halfway between its maximum height and minimum height.
  • progress == 1.0 means the bar is at its minimum height.

Basic Setup

A good starting place is to have a project with some kind of scrolling view (i.e. UITableView, UICollectionView, UIWebView, UIScrollView, etc). Make sure you've set up a property to access your scrolling view since we'll need to set its delegate property later on.

NOTE: Because UITableViewController's view property is the same as its tableView property, adding a BLKFlexibleHeightBar instance as a subview of a UITableViewController's view results in the bar being a subview of the tableView. I personally recommend just using a plain old UIViewController so you can fully control its view's subviews. Alternatively, see this stackoverflow post.

First, import the main BLKFlexibleHeightBar header into the class where you'll be configuring the bar.

#import "BLKFlexibleHeightBar.h"

Next, create an instance of BLKFlexibleHeightBar and configure it. When we initWithFrame:, the bar's maximumBarHeight property is autmatically set to the frame's height. We can manually set the minimumBarHeight from its default value of 20.0. Lastly, we can give it a color and add our bar to the view hierarchy.

BLKFlexibleHeightBar *myBar = [[BLKFlexibleHeightBar alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 100.0)];
myBar.minimumBarHeight = 50.0;

myBar.backgroundColor = [UIColor colorWithRed:0.86 green:0.25 blue:0.23 alpha:1];
[self.view addSubview:myBar];

Configuring bar behavior

Now we've got a bar with no subviews and no behavior, but a defined maximum height and minimum height.

To give the bar a behavior, we can use one of the included behaviors. Square Cash's bar behavior is simple to understand. When scrolled to the top, the bar is at its maximum height. As the user scrolls down, the bar begins to hide. The only way to make the bar visible again is by scrolling to the top.

#import "SquareCashStyleBehaviorDefiner.h"

The SquareCashStyleBehaviorDefiner (inherits from BLKFlexibleHeightBarBehaviorDefiner) contains all of the logic that controls how and when the height of the bar changes.

Set myBar's behaviorDefiner property to an instance of SquareCashStyleBehaviorDefiner.

myBar.behaviorDefiner = [SquareCashStyleBehaviorDefiner new];

The behavior of a BLKFlexibleHeightBarBehaviorDefiner is directly dependent on what's going on with our scrolling view. Therefore, BLKFlexibleHeightBarBehaviorDefiner (and of course, all of its subclasses) conform to UIScrollViewDelegate.

Set your scrolling view's UIScrollView delegate property to myBar's behaviorDefiner property (casting if necessary). This gives our behavior definer the information it needs from our scrolling view to properly control the height of our bar.

self.tableView.delegate = (id<UITableViewDelegate>)myBar.behaviorDefiner;

Snapping behavior (optional)

Snapping forces your bar to animate to a final position when the user stops scrolling. Any subclass of BLKFlexibleHeightBarBehaviorDefiner automatically gets snapping functionality for free. Snapping works by defining a final bar progress to which the bar will animate whenever the user stops scrolling and the bar is between some range of progress values.

[myBar.behaviorDefiner addSnappingPositionProgress:0.0 forProgressRangeStart:0.0 end:0.5];
[myBar.behaviorDefiner addSnappingPositionProgress:1.0 forProgressRangeStart:0.5 end:1.0];

The above code simply causes the bar to snap to the maxmium height (progress == 0.0) or minimum height (progress == 1.0) depending on which is closer. Additional snapping positions can be defined and don't necessarily have to follow the "whichever is closer" rule.

Configuring subviews

Subviews of a BLKFlexibleHeightBar instance define layout attribtes (frame, alpha, transform, etc.) for key progress values.

At progress == 0.0 (maximum bar height), your subview can have alpha == 1.0.

At progress == 1.0 (minimum bar height), your subview can have alpha == 0.0 and transform == CGAffineTransformMakeScale(0.2, 0.2)

As the bar condenses from its maximum height to its minimum height, your subview will smoothly shrink and fade away.

Start by creating and adding a subview to your bar. Don't bother giving it a frame - the layout attributes it defines in the next step will determine how it looks and where it appears.

UILabel *label = [[UILabel alloc] init];
label.text = @"TrendyStartup.io";
label.font = [UIFont systemFontOfSize:25.0];
label.textColor = [UIColor whiteColor];
[label sizeToFit];
[myBar addSubview:label];

Next, we'll configure layout attributes for all of the discrete layout states of the subview. For this example, we want our label to fade, shrink, and slide up as the bar shrinks, disappearing entirely when the bar is fully condensed. We'll need to define 2 discrete states for our subview - the initial state, where the subview is entirely visible and full size, and the final state, where the subview is faded away and no longer visible. All of the in-between states will be automatically filled in and with a smooth transition.

We define these discrete layout states by defining layout attributes for a subview using the BLKFlexibleHeightBarSubviewLayoutAttributes class.

BLKFlexibleHeightBarSubviewLayoutAttributes *initialLayoutAttributes = [BLKFlexibleHeightBarSubviewLayoutAttributes new];
initialLayoutAttributes.size = label.frame.size;
initialLayoutAttributes.center = CGPointMake(CGRectGetMidX(myBar.bounds), CGRectGetMidY(myBar.bounds)+10.0);

// This is what we want the bar to look like at its maximum height (progress == 0.0)
[label addLayoutAttributes:initialLayoutAttributes forProgress:0.0];

and then

// Create a final set of layout attributes based on the same values as the initial layout attributes
BLKFlexibleHeightBarSubviewLayoutAttributes *finalLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] initWithExistingLayoutAttributes:initialLayoutAttributes];
finalLayoutAttributes.alpha = 0.0;
CGAffineTransform translation = CGAffineTransformMakeTranslation(0.0, -30.0);
CGAffineTransform scale = CGAffineTransformMakeScale(0.2, 0.2);
finalLayoutAttributes.transform = CGAffineTransformConcat(scale, translation);

// This is what we want the bar to look like at its minimum height (progress == 1.0)
[label addLayoutAttributes:finalLayoutAttributes forProgress:1.0];

More layout attributes and more subviews can be added in exactly the same way, allowing you to create just about any flexible bar design imaginable.

Congrats! You should now have something that looks and behaves like this:

Demo

Creating custom behavior definers

If one of the included behavior definers isn't what you're looking for in your app, creating your own custom behavior definer might be the way to go.

In order to support any kind of behavior, BLKFlexibleHeightBar was designed to feature a plug-n-play architecure for bar behaviors. By subclassing BLKFlexibleHeightBarBehaviorDefiner, developers can have complete control over how and when a bar's progress property (and therefore, height) is updated.

  • In most scenarios, BLKFlexibleHeightBarBehaviorDefiner isn't useful until subclassed. By itself, it only provides snapping functionality and a property that controls whether or not the bar bounces when it reaches its maximum height. It makes no attempt to adjust the height of the bar during scrolling.

Subclassing guidelines

Start by creating a subclass BLKFlexibleHeightBarBehaviorDefiner.

The basic pattern for the definer is as follows:

  1. Implement UIScrollViewDelegate protocol methods. -scrollViewDidScroll: is generally a useful starting point.
  2. Based on the current scroll position in -scrollViewDidScroll:, calculate a new progress value for the behavior definer's flexibleHeightBar property. It will be useful to ask the flexibleHeightBar for its maximumBarHeight and minimumBarHeight properties.
  3. Set self.flexibleHeightBar.progress to the calculated value from step 2.
  4. Notify the behavior definer's flexibleHeightBar that it needs to re-layout using [self.flexibleHeightBar setNeedsLayout]

It may be useful to make other calculations outside of -scrollViewDidScroll:. For example, the included FacebookStyleBehaviorDefiner needs to apply scrolling thresholds before the bar should hide or reveal itself. This calculation is done inside of -scrollViewWillBeginDragging:.

TODO

  • Include a SafariStyleBehaviorDefiner (uses velocity, not just scroll position).
  • Support for Auto Layout based layout attributes would simplify some of the trickier bar designs, removing the need to perform final frame and size calculations yourself when defining layout attributes.

Let me know what you think!

You can get in touch with me via Twitter @BKyourway19

blkflexibleheightbar's People

Contributors

bryankeller avatar marcferna 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  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

blkflexibleheightbar's Issues

ScrollView setContentOffset not working after setup BLKFlexibleHeightBar.

Hi all,
I have created a view pager with a ScrollView embedded in a BLKFlexibleHeightBar like ones on Android. The scrollview contains many tabs. The custom bar work great: pages with root view are tableview(s) or scrollview(s) scroll and the bar go up and down as expected. But I have a small problem: I can't update the scrollview contentOffset after the bar setup completely. If I set the scrollview contentOffset before initialising the bar, it show with an offset on the bar. Can anyone tell me what ways to do this task? Thanks and sorry for my bad English.

Usage inside NavigationViewController

I have a UITabBarController with view controllers embedded in NavigationViewControllers.

Can I use this in a view controller embedded in a NavigationController inside a TAbBarController?

BLKDelegateSplitter does not work for scrollView delegate calls

I'm attempting to implement scrollViewDidScroll for my UITableView, but the splitter doesn't work with it for some reason. If I set my delegate like this, scrollViewDidScroll is called: tableView.delegate = self. But if I set it to the splitter, the scrollview method isn't called, even though the TableView Delegate methods are called:

delegateSplitter = BLKDelegateSplitter(firstDelegate: flexBar.behaviorDefiner, secondDelegate: self)
activityTable.delegate = delegateSplitter

Really not sure how to fix this, any pointers would be helpful.

BLKDelegateSplitter causing issues

Whenever I use BLKDelegateSplitter rather than self.tableView.delegate = self, it is crashing the app on click on on scroll. The error I am getting is:

-[__NSCFString scrollViewDidScroll:]: unrecognized selector sent to instance. 

When I just assign the delegate to the behaviorDefiner, it also works as intended. I looked through the issues but I couldn't find anything related to this.

I have tried swapping the first and second selector.

I am using version 1.0.2.

taps, touchBegan doesn't work anymore

when i replaced my custom header with flexible, then any taps is not received anymore. I track my taps for custom logic and now it's not catching anymore. Any ideas how to fix?

Cannot reuse initialViewLayoutAttributes?

I tried to reuse initialViewLayoutAttributes like below:
I have two subviews, and each time I just reuse the initial and final layout attributes. However at run time, I found the self.titleView's initial frame is already same as self.navigationCollectionView.

I had to create two copies for each view, and the titleView frame is correct then. Is this a bug?

    // configure layout attributes for titleView
    BLKFlexibleHeightBarSubviewLayoutAttributes *initialViewLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] init];
    initialViewLayoutAttributes.frame = CGRectMake(0,0,self.view.bounds.size.width,64);
    BLKFlexibleHeightBarSubviewLayoutAttributes *finalViewLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] initWithExistingLayoutAttributes:initialViewLayoutAttributes];
    finalViewLayoutAttributes.transform = CGAffineTransformMakeTranslation(0, -44);
    [self.titleView addLayoutAttributes:initialViewLayoutAttributes forProgress:0.0];
    [self.titleView addLayoutAttributes:finalViewLayoutAttributes forProgress:1.0];

    // configure layout attributes for navigationCollectionView
    initialViewLayoutAttributes.frame = CGRectMake(0,64,self.view.bounds.size.width,44);
    finalViewLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] initWithExistingLayoutAttributes:initialViewLayoutAttributes];
    finalViewLayoutAttributes.transform = CGAffineTransformMakeTranslation(0, -44);
    [self.navigationCollectionView addLayoutAttributes:initialViewLayoutAttributes forProgress:0.0];
    [self.navigationCollectionView addLayoutAttributes:finalViewLayoutAttributes forProgress:1.0];

BLKDelegateSplitter crash

I don't have a scenario yet to reproduce the crash, but sometimes I receive this:
[BLKDelegateSplitter scrollViewDidScroll:]: unrecognized selector sent to instance 0x18380150

Does anyone have a fix for it?

does not work with swift ?

I have tested BLKFlexibleHeightBar in my project, but it just show no effect.
And i could not find the reason. Could anyone help me? Many thanks!!

my test project repo:
https://github.com/gantoday/BLKFlexibleHeightBar-test

my viewController:

import UIKit
import BLKFlexibleHeightBar


class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let myBar = BLKFlexibleHeightBar(frame: CGRectMake(0.0, 0.0, self.view.frame.size.width, 100.0))
        myBar.minimumBarHeight = 20
        myBar.backgroundColor = UIColor.RedColor()

        myBar.behaviorDefiner = SquareCashStyleBehaviorDefiner()
        myBar.behaviorDefiner.addSnappingPositionProgress(0.0, forProgressRangeStart: 0.0, end: 0.5)
        myBar.behaviorDefiner.addSnappingPositionProgress(1.0, forProgressRangeStart: 0.5, end: 1.0)

        self.tableView.delegate = myBar.behaviorDefiner as? UITableViewDelegate

        self.view.addSubview(myBar)

        self.tableView.contentInset = UIEdgeInsetsMake(myBar.maximumBarHeight, 0.0, 0.0, 0.0);

        let label = UILabel();
        label.text = "hello word"
        label.font = UIFont.systemFontOfSize(25.0)
        label.textColor = UIColor.whiteColor()
        label.sizeToFit()
        myBar.addSubview(label)

        let initialLayoutAttributes = BLKFlexibleHeightBarSubviewLayoutAttributes()
        initialLayoutAttributes.size = label.frame.size
        initialLayoutAttributes.center = CGPointMake(CGRectGetMidX(myBar.bounds), CGRectGetMidY(myBar.bounds) + 10.0)
        label.addLayoutAttributes(initialLayoutAttributes, forProgress: 0.0)


        let finalLayoutAttributes = BLKFlexibleHeightBarSubviewLayoutAttributes(existingLayoutAttributes: initialLayoutAttributes)
        finalLayoutAttributes.alpha = 0.0
        let translation = CGAffineTransformMakeTranslation(0.0, -30.0)
        let scale = CGAffineTransformMakeScale(0.2, 0.2)
        finalLayoutAttributes.transform = CGAffineTransformConcat(scale, translation)
        label.addLayoutAttributes(finalLayoutAttributes, forProgress: 1.0)

    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 30
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) 

        return cell

    }

}

support AutoLayout

awesome library! when do you plan to support AutoLayout? I can't wait to see

how to fix tableview scrolling?

Before i integrated flexible bar, my table scrolled at correct position for cell via:

[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];

first reload - refresh cell and change the height of row, but scrolling after that is not working anymore.
here is video:
https://www.dropbox.com/s/bp937vhsm3izvru/bug%20scroll.mov?dl=0

correct position - when editor is fit totally to screen. How to fix it? i don't wanna to remove your bar, because i already integrated and liked abit :)

Changing height of the bar

Hi Bryan,
First of all great work. This library is awesome.

Is there any option to change the height of the bar by swiping over the bar (or any other action on the bar itself) rather than scrolling the tableview? Since my project requires the bar to cover the whole view initially, scrolling tableview is not an option for me.

Thanks.

UITableView not rendered correctly

Hi all,

I have an issue when adding the navigation bar with an UITableView. When the screen is loaded the table is not correctly rendered below the navigation bar. Once I start scrolling, the navigation bar jumps on top and from that moment the table looks fine.

Can someone has a clue what might be the problem?

img_0231
img_0232

Thanks.

Delegate splitter does not work

I don't think delegate splitter works. You have the following code in your SquareCashStyleViewController demo:

self.delegateSplitter = [[BLKDelegateSplitter alloc] initWithFirstDelegate:behaviorDefiner secondDelegate: self];
self.tableView.delegate = (id)self.delegateSplitter;

tableview delage functions does not work such as:

  • (void)scrollViewDidScroll:(UIScrollView *)scrollView

However, when I use self as the first delegate and the behaviorDefiner as the second delegate then tableview delegate works but then nav bar stops working

self.delegateSplitter = [[BLKDelegateSplitter alloc] initWithFirstDelegate:behaviorDefiner secondDelegate: self];

is this a bug or am I missing something

P.S. the same in swift

proxy object

hi
first thanks for your great work.
i have problem when use UITebleView and want to use my scrollViewDelegate.
i suggest to implement like this control:

https://github.com/ninjinkun/NJKScrollFullScreen

_scrollProxy = [[NJKScrollFullScreen alloc] initWithForwardTarget:self]; // UIScrollViewDelegate and UITableViewDelegate methods proxy to ViewController
// and in NJKScrollFullScreen Class

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if ([_forwardTarget respondsToSelector:@selector(scrollViewDidScroll:)]) {
        [_forwardTarget scrollViewDidScroll:scrollView];
    }
    ........
}

Scroll resistance between tableview and FlexibleHeightBar

Hi Bryan,

Is it possible to add a scroll resistance (rubber band effect) between the FelexibleHeightBar and the tableview? What I mean is the Bar should stays at the minimum height until the tableview is pulled down and top of the tableview reaches some distance from the bottom of the bar. Most of the pull to refresh libraries adds this type of effect.
I believe this feature is not the scope of this project but if you could include it or provide some guidance on implementing, it would be really helpful.

Thanks

Swift compatibility

Hi,

I was trying to get this setup on a Swift project and noticed that it wouldn't allow me to use the tableView delegate using BLKDelegateSplitter or through `myBar.behaviorDefiner)

Inspecting the object leads me to believe that it doesn't understand how to cast it as UITableView delegate on either end. Here are the forms I've tried:

  • tableView.delegate = self displays the bar but does not allow the bar to snap
  • tableView.delegate = behavior as UITableViewDelegate crashes immediately and yields warning of "Treating a forced downcast to UITableViewDelegate as optional will never produce nil"
  • tableView.delegate = behavior as? UITableViewDelegate loads up the view but the delegate is nil
  • tableView.delegate = (behavior as UITableViewDelegate) silences the second warning but crashes because of nil value
  • tableView.delegate = BLKDelegateSplitter(firstDelegate: behavior, secondDelegate: self) as? UITableViewDelegate also yields nil

I tried recreating the Objective-C demo for the Square style and got the same results. Do you intend to add Swift support in the near future?

ios 7 support

Thanks for the great library! Does it support iOS7? I'm getting a consistent crash when I scroll with iOS7 devices

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Auto Layout still required after executing -layoutSubviews. BLKFlexibleHeightBar's implementation of -layoutSubviews needs to call super.'

Problem with Grouped TableView

Thanks for this great library. Please add the following code to the SquareCashStyleViewController.m in the demo project to replicate the issue:

  • (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    return 2;
    }
  • (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
    {
    return @"This view will be out of place";
    }

The group's header view does not move up with the custom bar when scrolling up.

Incorrect NavBar behaviour

I noticed that when tableview has less than three cells FacebookStyleBar misbehaves. I got this behaviour in my code as well as the provided demo code in this repository. However it works fine when there are lot of cells

Am i missing something?

How can I snap the progress to 1 right after my FlexibleHeightBar initialized?

I have a search bar on top of a UIScrollView, and I'd like to hide the searchBar initially. And show the search bar when scrollView scrolls up, code like this:

- (void)viewDidLoad {
    ...
    searchBar = [[BLKFlexibleHeightBar alloc] initWithFrame:CGRectMake(0, 0, width, 64)];
    searchBar.minimumBarHeight = 0;
    searchBar.maximumBarHeight = 64;

    searchBar.backgroundColor = [UIColor colorWithRed:0.86 green:0.25 blue:0.23 alpha:1];
    searchBar.behaviorDefiner = [SquareCashStyleBehaviorDefiner new];
    [searchBar.behaviorDefiner addSnappingPositionProgress:0.0 forProgressRangeStart:0.0 end:0.5];
    [searchBar.behaviorDefiner addSnappingPositionProgress:1.0 forProgressRangeStart:0.5 end:1.0];

    _scrollView.delegate = (id<UITableViewDelegate>)searchBar.behaviorDefiner;
    [_scrollView addSubview:searchBar];

    [searchBar.behaviorDefiner snapToProgress:1.0 scrollView:_scrollView];
}

but a searchBar is appear in maximum height on the _scrollView... So I add an RACObserve on searchBar.process like:

[RACObserve(searchBar, progress) subscribeNext:^(id x) {
    NSLog(@"process %f", searchBar.progress);
}];

Logs:

process 0.000000
process 1.000000
process 1.000000
process 0.000000

The searchBar's process snapped to 1, the then confusedly snapped back to 0....

snapping issue while switching bewteen UICollectionViews

I have two tabs, each tab contains a UICollectionView, and a BLKHeightBar as the shared title view.
snap is enabled and set to 0.5 threshold.

tab 1 contains 6 cells and tab 2 containts 20 cells, so normally, tab 1 will always bounce back to progress 0, while tab 2 can snap to 1 and 0.

When I switch to tab 2, scroll tab 2 and make it snap to progress 1, and then I switch to tab 1, while the height bar stays at progress 1,

Then when I switch again back to tab 2, now I cannot snap tab 2 back to progress 0. When I see the self.flexibleHeightBar.progress is set to 0, after that it is snapping back to progress 1, which is wrong. I feel it should not snap to progress 1 while self.flexibleHeightBar.progress == 1.

It seems like some variable is not updating the current scroll view properties?
How could I continue debug it and fix it?

Problems synchronising the bar with table view scrolling.

I am not able to synchronising my tableview with the scrolling of the appbar.
I am new into ios developement and only use programming(no interface builders or storyboard), so I need to Know amethod by which i can change the 'y' of the frame of my table w.r.t. the bar size changes , maybe a delegate method.

here is alittle snippet....

myBar = [[BLKFlexibleHeightBar alloc] initWithFrame:CGRectMake(0.0, 20.0, self.view.frame.size.width, 100.0)];
myBar.minimumBarHeight = 50.0;
myBar.behaviorDefiner = [SquareCashStyleBehaviorDefiner new];
myBar.backgroundColor = [UIColor colorWithRed:0.86 green:0.25 blue:0.23 alpha:1];
[myBar.behaviorDefiner addSnappingPositionProgress:0.0 forProgressRangeStart:0.0 end:0.5];
[myBar.behaviorDefiner addSnappingPositionProgress:1.0 forProgressRangeStart:0.5 end:1.0];
[self.view addSubview:myBar];

address_table=[[UITableView alloc]initWithFrame:CGRectMake(0, myBar.frame.origin.y, DEVICE_SIZE.width, DEVICE_SIZE.height-(myBar.frame.origin.y))];
address_table.backgroundColor=[UIColor clearColor];
[address_table setSeparatorStyle:UITableViewCellSeparatorStyleNone];
address_table.contentInset = UIEdgeInsetsMake(myBar.maximumBarHeight, 0.0, 0.0, 0.0);

[address_table setDelegate:self];
self.delegateSplitter = [[BLKDelegateSplitter alloc] initWithFirstDelegate:myBar.behaviorDefiner secondDelegate:self];
address_table.delegate = (id)self.delegateSplitter;
[address_table setDataSource:self];
[address_table reloadData];
[self.view addSubview:address_table];

Here is the screenshot.... Please help..

img_0026 1

problem with deleting tableview rows

Hi,

first thanks for the great work. Your code is exactly what i need.
But i have a problem by deleting tableview rows.

If i have 3 or 4 bigger cells on my tableview and if i want delete them, the BLKFlexibleHeightBar don't
scroll down automatically to "maximumBarHeight". I have to scroll down manually to see the bar again.
Is there any solution for my problem? the red bar above is the navigation bar not the BLKFlexibleHeightBar. My minimumBarHeight is zero.

bildschirmfoto 2015-03-19 um 12 26 00

sorry for my english

problem with elasticMaximumHeightAtTop when I need a negative progress

Firstly, thank you for this great work, it helps me a lot.We know that elasticMaximumHeightAtTop determine whether can stretch to larger sizes than it's maximumBarHeight,so that, a negative progress.
As code in - (void)setProgress:(CGFloat)progress;

 - (void)setProgress:(CGFloat)progress
{
    _progress = fmin(progress, 1.0);
   //if isElasticMaximumHeightAtTop is YES, a negative progress will not be changed to 0.0.
    if((self.behaviorDefiner && !self.behaviorDefiner.isElasticMaximumHeightAtTop) || !self.behaviorDefiner)
    {
        _progress = fmax(_progress, 0.0);
    }
}

However,code in layoutSubviews did the opposite thing.

- (void)layoutSubviews
{
    [super layoutSubviews];

    // Update height
    CGRect barFrame = self.frame;
    barFrame.size.height = [self interpolateFromValue:self.maximumBarHeight toValue:self.minimumBarHeight withProgress:self.progress];
    self.frame = barFrame;

   //if  isElasticMaximumHeightAtTop is YES, a negative progress will be changed to 0.0
    if(self.behaviorDefiner && self.behaviorDefiner.isElasticMaximumHeightAtTop)
    {
        self.progress = fmax(self.progress, 0.0);
    }
   ......
}

the result is a negative progress will be changed to 0.0 when layoutSubviews.I delete the below code in layoutSubviews for my goal.

 if(self.behaviorDefiner && self.behaviorDefiner.isElasticMaximumHeightAtTop)
 {
        self.progress = fmax(self.progress, 0.0);
 }

Fast swiping down cause flexibleHeader not take effect immediately

when I scroll down slowly my custom flexible header smoothly comes down. but when I scroll down fast, flexible header stuck in its place! I don't see this effect when I scroll up fast.
here is the gif:
scroll

my workaround is override setProgress: in my custom flexible header and reposition imageView manually:

- (void)setProgress:(CGFloat)progress
{
    [super setProgress:progress];   
    if (progress<0) {
        self.imageView.y = navBarHeight;
    }
}

What if there is navigationBar present?

I have a UIViewController inside a UINavigationController as well as UITabBarController. I have 2 UIViews, one being the month name and the other being a weekly view. I obviously have a navBar that contains 3 UIBarButtonItems. How would I go about configuring this flexible height bar to work with the navBar and my two UIViews, which are all set in the storyboard?

CollectionView Problem

Hello i have a problem with a collectionView in BLKFlexibleHeightBar.

I add the as Subview collectionView in the HeightBar View. The collectionView set to only scroll Horizontal, when i scroll the collectionView on the top to next page, and scroll up or down the (ScrollView or TableView) than reload the collectionView an set the contentoffset.x to 0.

Has anyone an idea?

delegate

the delegate is not self ,how could response the didSelectRow event?

Broken indicator insets

I don't know exactly what is happening but the #33 break the indicator insets for my UITableView. If I comment the line in scrollViewDidScroll in BLKFlexibleHeightBarBehaviorDefiner then the indicator insets are as expected.

My setup:
A flexibleHeightBar and a tableView are subviews of a UIViewController
I use autoLayout and all my constraints are define in code

A method to set the progress to 0 would be nice

I'm using a flexBar in a view with two tableViews, and I have the following (self inflicted) issue — when I scroll down the first tableView, it collapses the bar. But when I switch to the second view, the bar is still collapsed, and can't be pulled down (see my video). Both of the scroll views delegates split to the flexBar, which actually seems to work fine except for this small thing. A simple fix would be a method I could call to un-collapse the flexBar when it switches (with an animation), which works fine for me. Thanks!

YouTube video of issue

Bar covers UITableView

I am currently building an app using Swift and the UITableView takes a place an entire view.
When I apply the bar, the bar overlaps the top of the tableview covering first cell, not like examples GIFs.
Is there a built-in way to solve this problem?

Thanks :)

weird _adjustContentOffsetIfNecessary changed my contentOffset

I have two tabs, each contains one UICollectionView. I embed SVPullToRefresh in each UICollectionView as well. I set up the snapping by 0.5 threshold for BLK height bar.

tab 1 has 6 cells and tab 2 has 20 cells, so tab 2 could snap to progress 1, while tab 1 cannot.
My behaviour is copied from Facebook style behaviour:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if(!self.isCurrentlySnapping)
    {
        CGFloat deltaYOffset = scrollView.contentOffset.y - self.previousYOffset;
        CGFloat deltaProgress = deltaYOffset / (self.flexibleHeightBar.maximumBarHeight-self.flexibleHeightBar.minimumBarHeight);

        self.flexibleHeightBar.progress = self.previousProgress + deltaProgress;
        NSLog(@"contentOffset Y %f, previousYOffset:%f, progress %f",scrollView.contentOffset.y,self.previousYOffset, self.previousProgress + deltaProgress);

        [self.flexibleHeightBar setNeedsLayout];
    }
}

everytime when switching tab, I will update the UICollectionView like this:

targetCollection.delegate = (id<UICollectionViewDelegate>)self.delegateSplitter;
targetCollection.contentOffset = CGPointMake(targetCollection.contentOffset.x, -CGRectGetHeight(self.BLKBar.frame));

the second line is to keep the BLKBar height consistent while switching between tabs. e.g. When the BLK height bar is at minimum height, I should keep it, so I need to update the offset when switching to target tab.

Steps:
First, I switch from tab 1 to tab 2; BLKBar is at progress 0;
when I am on tab 2, I scroll the UICollectionView, snap BLKBar to progress 1;
Then I switch to tab 1 by paning horizontally, ideally the BLK Bar should keep the snapping at progress 1, aka minimum height, however, I found it is at progress 0!

In order to debug, I subclass a HackUICollectionView to see what is happenning.

I setup my BLKBar minimum height is 64, max height is 108.

so while debugging, after
targetCollection.contentOffset = CGPointMake(targetCollection.contentOffset.x, -CGRectGetHeight(self.BLKBar.frame));
is set to (0,-64),

there is one API called _adjustContentOffsetIfNecessary changed my contentOffset to -108:

...
    frame #8: 0x000000010a008bda UIKit`-[UIScrollView setContentOffset:] + 645
    frame #9: 0x000000010969e3ca MCompass`-[HackUICollectionView setContentOffset:](self=0x00007f8279854e00, _cmd=0x000000010a765895, contentOffset=(x = 0, y = -108)) + 74 at HackUICollectionView.m:14
    frame #10: 0x0000000109b5bbf6 Foundation`_NSSetPointValueAndNotify + 139
    frame #11: 0x000000010a01d535 UIKit`-[UIScrollView(UIScrollViewInternal) _adjustContentOffsetIfNecessary] + 1445
    frame #12: 0x000000010a01a727 UIKit`-[UIScrollView(UIScrollViewInternal) _stopScrollingNotify:pin:tramplingDragFlags:] + 417
...

If I override _adjustContentOffsetIfNecessary in sub class, it will not change it to -108 obviously, but I CANNOT fix my problem by this way because it is a internal API, I cannot simply pass through it.

Any idea why this happened? How can I keep the progress while switching UICollectionViews?

Use library in tabbar?

Hi. Thanks you for great library. I need use it in a child of tabberController, but it not work as expect.
It seem the SquareCashStyleBehaviorDefiner did not add to top of child view. You can see my attack to know more information:

screen shot 2018-04-02 at 22 40 33

Thanks you

Table View Headers — how to implement?

I'm currently having my UITableView fill the view entirely, and setting the content inset to the max height of my flexible bar. This works great without headers, but when I have section headers on my tableview, they are pushed down due to the content inset. Is there a proper way to do this, or do I need to do something hacky? See the photos for details of what I mean.
Before scroll
After scroll — section header is out of place

How to pin a subview in BLKFlexibleHeightBar

I am trying to modify the demo FacebookStyleBar.m:

I am looking for that when user scrolls down, the whiteView keeps the height, just moves up along with the blueBarView, not shrinking, and when the blueBarView is out of screen, the whiteView will stay pinned to top screen,

I am trying to modify finalWhiteBarLayoutAttributes.transform to below, which I definitely misunderstood:

    BLKFlexibleHeightBarSubviewLayoutAttributes *finalWhiteBarLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] init];
    finalBlueBarLayoutAttributes.frame = CGRectMake(0, 20, self.frame.size.width, 40);
    [whiteBarView addLayoutAttributes:finalWhiteBarLayoutAttributes forProgress:1];

the animation is totally messed up while scrolling.

I tried to use follow the demo code

    BLKFlexibleHeightBarSubviewLayoutAttributes *finalWhiteBarLayoutAttributes = [[BLKFlexibleHeightBarSubviewLayoutAttributes alloc] initWithExistingLayoutAttributes:initialWhiteBarLayoutAttributes];
    finalWhiteBarLayoutAttributes.transform = CGAffineTransformMakeTranslation(0, -(105-20-40));
    [whiteBarView addLayoutAttributes:finalWhiteBarLayoutAttributes forProgress:1];

but still performs as the old style.

Could you take a look where am I wrong? Just want the whiteView keep it's size and moves up to the top margin

Starting to scroll from the bar

Hello,

First of all great library ! That being said, would it be possible to start the process of stretching the bar, as you start scrolling from that bar itself. I hope you get me, now it only works (at least for me) if i start scrolling from what's below my bar, not from the bar itself.

Thanks :)

Not working with Swift

Hello i try to use this repo but this is not working in swift.

Gives an problem with the tableview.delegate downcast, has anyone solution for this problem?

Greetz

FacebookStyleBarBehaviorDefiner with pagination

So we have UITableView which is used in our app and FacebookStyleBarBehaviorDefiner perfectly matches our requirements, but we have one issue...
Our UITableView is aable to load more stuff - pagination. While we load new page contentOffset changes and BLKFlexibleHeightBar is presented out of nothing, which creates this weird behavior.

Looks like this code is responsible for what's happening:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if(!self.isCurrentlySnapping)
    {
        CGFloat deltaYOffset = scrollView.contentOffset.y - self.previousYOffset;
        CGFloat deltaProgress = deltaYOffset / (self.flexibleHeightBar.maximumBarHeight-self.flexibleHeightBar.minimumBarHeight);

        self.flexibleHeightBar.progress = self.previousProgress + deltaProgress;

        [self.flexibleHeightBar setNeedsLayout];
    }
}

So when I log what values do I have there I've noticed that at some point deltaYOffset is negative when it shouldn't while I'm scrolling to the bottom. I've changed this, so I always get positive number there, but then I wasn't able to scroll to the top to see the bar again.

Any ideas how to solve this?

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.