facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.7k stars 24.29k forks source link

UISearchBar cannot display #1270

Closed bolasblack closed 9 years ago

bolasblack commented 9 years ago

My Obj-C Code:

    #import <UIKit/UIKit.h>
    #import "RCTViewManager.h"

    @interface RCTSearchBarTest : RCTViewManager
    @end

    @implementation RCTSearchBarTest

    RCT_EXPORT_MODULE()

    - (UISearchBar *)view
    {
      return [[UISearchBar alloc] init];
    }

    @end

My js code:

    var {requireNativeComponent} = React;
    var RCTSearchBarTest = requireNativeComponent('RCTSearchBarTest', null);
    var App = React.createClass({
      render: function() {
        <View>
          <RCTSearchBarTest />
        </View>
      }
    })

I learned it from React-Native's document: https://facebook.github.io/react-native/docs/nativecomponentsios.html

I tried Reveal, the UISearchBar is exist, but not displayed.

After I add code [searchBar setFrame:CGRectMake(0, 0, 375, 44)];, it works, but I lookup from React-Native's code I didn't found anything like this.

Actual code: CoffeeScript, Objective-C

Is anything I missed?

umhan35 commented 9 years ago

Some native components are using ComponentHeight provided from Obj-C code.

Before anyone comes here, you can search ComponentHeight in this repo. The height for DatePicker and SegmentedControl is explicitly set just like what you did.

bolasblack commented 9 years ago

@umhan35 I tried the way you said, not work for me :(

umhan35 commented 9 years ago

It will be something looks like this:

In your Obj-C code:

- (NSDictionary *)constantsToExport
{
  RCTSearchBar *view = [[RCTSearchBar alloc] init];
  return @{
           @"ComponentHeight": @(view.intrinsicContentSize.height),
           };
}

JS:

NativeModules = require('NativeModules');

...

style={{height: NativeModules.SearchBarManager.ComponentHeight}}

...
bolasblack commented 9 years ago

@umhan35 You can see my code: CoffeeScript, Objective-C, I have tried this :(

umhan35 commented 9 years ago

Try my one. Mine works before I post it. Try to use the dirty inline style.

bolasblack commented 9 years ago

@umhan35 I tried just now, but nothing changed :'(

brentvatne commented 9 years ago

@umhan35's approach seems solid - check out the RCTDatePickerManager for an example of how this can be done

bolasblack commented 9 years ago

I found the reason:

image

The UIView and UISearchBarBackground frame size become 0, 0, 0, 0, then I changed my code:

- (UISearchBar *)view
{
  UISearchBar *searchBar = [[UISearchBar alloc] init];

  UIView *subUIView = searchBar.subviews.firstObject;
  CGRect screenRect = [[UIScreen mainScreen] bounds];
  [subUIView setFrame:CGRectMake(0, 0, screenRect.size.width, searchBar.intrinsicContentSize.height)];
  [subUIView.subviews.firstObject setFrame:CGRectMake(0, 0, screenRect.size.width, searchBar.intrinsicContentSize.height)];

  return searchBar;
}

The issue resolved.

@brentvatne Maybe it's a bug of react-native?

umhan35 commented 9 years ago

It's not a bug. I've been using the solution I provided in my project.

Here are the obj-c and JS files. Check out the last method in RCTSearchBarManager.m. I thought I will open source this, but there are a lot of features provided by a search bar and I only use part of them.

RCTSearchBar.h

#import <UIKit/UIKit.h>

@class RCTEventDispatcher;

@interface RCTSearchBar : UISearchBar

- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;

@end

RCTSearchBar.m

#import "RCTSearchBar.h"

#import "UIView+React.h"
#import "RCTEventDispatcher.h"

@interface RCTSearchBar() <UISearchBarDelegate>

@end

@implementation RCTSearchBar
{
  RCTEventDispatcher *_eventDispatcher;
}

- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
  if ((self = [super initWithFrame:CGRectMake(0, 0, 1000, 44)])) {
    _eventDispatcher = eventDispatcher;
    self.delegate = self;
  }
  return self;
}

- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
  [self setShowsCancelButton:YES animated:YES];

  [_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus
                                 reactTag:self.reactTag
                                     text:searchBar.text];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
  [_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange
                                 reactTag:self.reactTag
                                     text:searchText];
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
  NSDictionary *event = @{
                          @"target": self.reactTag,
                          @"button": @"search",
                          @"searchText": searchBar.text
                          };

  [_eventDispatcher sendInputEventWithName:@"topTap" body:event];
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
  self.text = @"";
  [self resignFirstResponder];
  [self setShowsCancelButton:NO animated:YES];

  NSDictionary *event = @{
                          @"target": self.reactTag,
                          @"button": @"cancel"
                          };

  [_eventDispatcher sendInputEventWithName:@"topTap" body:event];
}

@end

RCTSearchBarManager.h

#import "RCTViewManager.h"

@interface RCTSearchBarManager : RCTViewManager

@end

RCTSearchBarManager.m

#import "RCTSearchBarManager.h"

#import "RCTSearchBar.h"

#import "RCTBridge.h"

@implementation RCTSearchBarManager

RCT_EXPORT_MODULE()

- (UIView *)view
{
//  RCTSearchBar *searchBar = [[RCTSearchBar alloc] initWithFrame:CGRectMake(0, 0, 1000, 44)];

  RCTSearchBar *searchBar = [[RCTSearchBar alloc] initWithEventDispatcher:self.bridge.eventDispatcher];
//  RCTSearchBar *searchBar = [[RCTSearchBar alloc] init];
//[[  UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:(UIViewController *)]

  return searchBar;
}

RCT_EXPORT_VIEW_PROPERTY(placeholder, NSString)
RCT_EXPORT_VIEW_PROPERTY(showsCancelButton, BOOL)

- (NSDictionary *)constantsToExport
{
  return @{
           @"ComponentHeight": @([self view].intrinsicContentSize.height),
           };
}

@end

search_bar.js

var NativeModules, PropTypes, RCTSearchBar, React, SearchBar;

React = require('react-native');

RCTSearchBar = React.requireNativeComponent('RCTSearchBar', null);

PropTypes = require('ReactPropTypes');

NativeModules = require('NativeModules');

SearchBar = React.createClass({
  propTypes: {
    placeholder: PropTypes.string,
    showsCancelButton: PropTypes.bool,
    onChange: PropTypes.func,
    onChangeText: PropTypes.func,
    onFocus: PropTypes.func,
    onSearchButtonPress: PropTypes.func,
    onCancelButtonPress: PropTypes.func
  },
  _onChange: function(e) {
    var base, base1;
    if (typeof (base = this.props).onChange === "function") {
      base.onChange(e);
    }
    return typeof (base1 = this.props).onChangeText === "function" ? base1.onChangeText(e.nativeEvent.text) : void 0;
  },
  _onPress: function(e) {
    var base, base1, button;
    button = e.nativeEvent.button;
    if (button === 'search') {
      return typeof (base = this.props).onSearchButtonPress === "function" ? base.onSearchButtonPress(e.nativeEvent.searchText) : void 0;
    } else if (button === 'cancel') {
      return typeof (base1 = this.props).onCancelButtonPress === "function" ? base1.onCancelButtonPress() : void 0;
    }
  },
  render: function() {
    return <RCTSearchBar
      style={{height: NativeModules.SearchBarManager.ComponentHeight}}
      onChange={this._onChange}
      onPress={this._onPress}
      {...this.props}
    />;
  }
});

module.exports = SearchBar;

//# sourceMappingURL=search_bar.js.map
umhan35 commented 9 years ago

@bolasblack I just open sourced react-native-search-bar on npm. Check it out on GitHub.

brentvatne commented 9 years ago

Nice one @umhan35!