mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-02-06 22:44:22 +08:00
Ported TabBarIOS to OSS and unified implementation
This commit is contained in:
29
Libraries/Components/TabBarIOS/TabBarIOS.android.js
Normal file
29
Libraries/Components/TabBarIOS/TabBarIOS.android.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TabBarIOS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var View = require('View');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
|
||||
var DummyTabBarIOS = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<View style={[this.props.style, styles.tabGroup]}>
|
||||
{this.props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
tabGroup: {
|
||||
flex: 1,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = DummyTabBarIOS;
|
||||
36
Libraries/Components/TabBarIOS/TabBarIOS.ios.js
Normal file
36
Libraries/Components/TabBarIOS/TabBarIOS.ios.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TabBarIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
|
||||
var TabBarIOS = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<RKTabBar style={[styles.tabGroup, this.props.style]}>
|
||||
{this.props.children}
|
||||
</RKTabBar>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
tabGroup: {
|
||||
flex: 1,
|
||||
}
|
||||
});
|
||||
|
||||
var config = {
|
||||
validAttributes: ReactIOSViewAttributes.UIView,
|
||||
uiViewClassName: 'RCTTabBar',
|
||||
};
|
||||
var RKTabBar = createReactIOSNativeComponentClass(config);
|
||||
|
||||
module.exports = TabBarIOS;
|
||||
38
Libraries/Components/TabBarIOS/TabBarItemIOS.android.js
Normal file
38
Libraries/Components/TabBarIOS/TabBarItemIOS.android.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TabBarItemIOS
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Dimensions = require('Dimensions');
|
||||
var React = require('React');
|
||||
var View = require('View');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
|
||||
var DummyTab = React.createClass({
|
||||
render: function() {
|
||||
if (!this.props.selected) {
|
||||
return <View />;
|
||||
}
|
||||
return (
|
||||
<View style={[this.props.style, styles.tab]}>
|
||||
{this.props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
tab: {
|
||||
// TODO(5405356): Implement overflow: visible so position: absolute isn't useless
|
||||
// position: 'absolute',
|
||||
width: Dimensions.get('window').width,
|
||||
height: Dimensions.get('window').height,
|
||||
borderColor: 'red',
|
||||
borderWidth: 1,
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = DummyTab;
|
||||
94
Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
Normal file
94
Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||
*
|
||||
* @providesModule TabBarItemIOS
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var Image = require('Image');
|
||||
var React = require('React');
|
||||
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
|
||||
var Dimensions = require('Dimensions');
|
||||
var StaticContainer = require('StaticContainer.react');
|
||||
var StyleSheet = require('StyleSheet');
|
||||
var View = require('View');
|
||||
|
||||
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
|
||||
var merge = require('merge');
|
||||
|
||||
var TabBarItemIOS = React.createClass({
|
||||
propTypes: {
|
||||
icon: Image.sourcePropType.isRequired,
|
||||
onPress: React.PropTypes.func.isRequired,
|
||||
selected: React.PropTypes.bool.isRequired,
|
||||
badgeValue: React.PropTypes.string,
|
||||
title: React.PropTypes.string,
|
||||
style: View.stylePropType,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
hasBeenSelected: false,
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
if (this.props.selected) {
|
||||
this.setState({hasBeenSelected: true});
|
||||
}
|
||||
},
|
||||
|
||||
componentWillReceiveProps: function(nextProps) {
|
||||
if (this.state.hasBeenSelected || nextProps.selected) {
|
||||
this.setState({hasBeenSelected: true});
|
||||
}
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var tabContents = null;
|
||||
// if the tab has already been shown once, always continue to show it so we
|
||||
// preserve state between tab transitions
|
||||
if (this.state.hasBeenSelected) {
|
||||
tabContents =
|
||||
<StaticContainer shouldUpdate={this.props.selected}>
|
||||
{this.props.children}
|
||||
</StaticContainer>;
|
||||
} else {
|
||||
tabContents = <View />;
|
||||
}
|
||||
|
||||
return (
|
||||
<RKTabBarItem
|
||||
icon={this.props.icon.uri}
|
||||
selectedIcon={this.props.selectedIcon && this.props.selectedIcon.uri}
|
||||
onPress={this.props.onPress}
|
||||
selected={this.props.selected}
|
||||
badgeValue={this.props.badgeValue}
|
||||
title={this.props.title}
|
||||
style={[styles.tab, this.props.style]}>
|
||||
{tabContents}
|
||||
</RKTabBarItem>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
tab: {
|
||||
position: 'absolute',
|
||||
width: Dimensions.get('window').width,
|
||||
height: Dimensions.get('window').height,
|
||||
}
|
||||
});
|
||||
|
||||
var RKTabBarItem = createReactIOSNativeComponentClass({
|
||||
validAttributes: merge(ReactIOSViewAttributes.UIView, {
|
||||
title: true,
|
||||
icon: true,
|
||||
selectedIcon: true,
|
||||
selected: true,
|
||||
badgeValue: true,
|
||||
}),
|
||||
uiViewClassName: 'RCTTabBarItem',
|
||||
});
|
||||
|
||||
module.exports = TabBarItemIOS;
|
||||
8
Libraries/Image/RCTGIFImage.h
Normal file
8
Libraries/Image/RCTGIFImage.h
Normal file
@@ -0,0 +1,8 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
extern CAKeyframeAnimation *RCTGIFImageWithData(NSData *data);
|
||||
extern CAKeyframeAnimation *RCTGIFImageWithFileURL(NSURL *URL);
|
||||
91
Libraries/Image/RCTGIFImage.m
Normal file
91
Libraries/Image/RCTGIFImage.m
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTGIFImage.h"
|
||||
|
||||
#import "RCTLog.h"
|
||||
|
||||
static CAKeyframeAnimation *RCTGIFImageWithImageSource(CGImageSourceRef imageSource)
|
||||
{
|
||||
if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF)) {
|
||||
CFRelease(imageSource);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
|
||||
NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
|
||||
|
||||
size_t imageCount = CGImageSourceGetCount(imageSource);
|
||||
NSTimeInterval duration = 0;
|
||||
NSMutableArray *delays = [NSMutableArray arrayWithCapacity:imageCount];
|
||||
NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount];
|
||||
for (size_t i = 0; i < imageCount; i++) {
|
||||
CGImageRef image = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
|
||||
NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, i, NULL);
|
||||
NSDictionary *frameGIFProperties = frameProperties[(id)kCGImagePropertyGIFDictionary];
|
||||
|
||||
const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
|
||||
NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime];
|
||||
if (delayTime == nil) {
|
||||
if (i == 0) {
|
||||
delayTime = @(kDelayTimeIntervalDefault);
|
||||
} else {
|
||||
delayTime = delays[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
const NSTimeInterval kDelayTimeIntervalMinimum = 0.02;
|
||||
if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) {
|
||||
delayTime = @(kDelayTimeIntervalDefault);
|
||||
}
|
||||
|
||||
duration += delayTime.doubleValue;
|
||||
delays[i] = delayTime;
|
||||
images[i] = (__bridge_transfer id)image;
|
||||
}
|
||||
|
||||
NSMutableArray *keyTimes = [NSMutableArray arrayWithCapacity:delays.count];
|
||||
NSTimeInterval runningDuration = 0;
|
||||
for (NSNumber *delayNumber in delays) {
|
||||
[keyTimes addObject:@(runningDuration / duration)];
|
||||
runningDuration += delayNumber.doubleValue;
|
||||
}
|
||||
|
||||
[keyTimes addObject:@1.0];
|
||||
|
||||
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
|
||||
animation.calculationMode = kCAAnimationDiscrete;
|
||||
animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
|
||||
animation.keyTimes = keyTimes;
|
||||
animation.values = images;
|
||||
animation.duration = duration;
|
||||
return animation;
|
||||
}
|
||||
|
||||
CAKeyframeAnimation *RCTGIFImageWithData(NSData *data)
|
||||
{
|
||||
if (data.length == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
|
||||
CAKeyframeAnimation *animation = RCTGIFImageWithImageSource(imageSource);
|
||||
CFRelease(imageSource);
|
||||
return animation;
|
||||
}
|
||||
|
||||
CAKeyframeAnimation *RCTGIFImageWithFileURL(NSURL *URL)
|
||||
{
|
||||
if (!URL) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (![URL isFileURL]) {
|
||||
RCTLogError(@"Loading remote image URLs synchronously is a really bad idea.");
|
||||
return nil;
|
||||
}
|
||||
|
||||
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)URL, NULL);
|
||||
CAKeyframeAnimation *animation = RCTGIFImageWithImageSource(imageSource);
|
||||
CFRelease(imageSource);
|
||||
return animation;
|
||||
}
|
||||
@@ -7,6 +7,9 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */; };
|
||||
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */; };
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */; };
|
||||
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */; };
|
||||
58B511901A9E6BD600147676 /* RCTNetworkImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118C1A9E6BD600147676 /* RCTNetworkImageView.m */; };
|
||||
58B511911A9E6BD600147676 /* RCTNetworkImageViewManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 58B5118E1A9E6BD600147676 /* RCTNetworkImageViewManager.m */; };
|
||||
@@ -25,7 +28,13 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
58B5115D1A9E6B3D00147676 /* libRCTNetworkImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTNetworkImage.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1304D5A71AA8C4A30002E2BE /* RCTStaticImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImage.h; sourceTree = "<group>"; };
|
||||
1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImage.m; sourceTree = "<group>"; };
|
||||
1304D5A91AA8C4A30002E2BE /* RCTStaticImageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTStaticImageManager.h; sourceTree = "<group>"; };
|
||||
1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTStaticImageManager.m; sourceTree = "<group>"; };
|
||||
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTGIFImage.h; sourceTree = "<group>"; };
|
||||
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTGIFImage.m; sourceTree = "<group>"; };
|
||||
58B5115D1A9E6B3D00147676 /* libRCTImage.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTImage.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
58B511891A9E6BD600147676 /* RCTImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTImageDownloader.h; sourceTree = "<group>"; };
|
||||
58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageDownloader.m; sourceTree = "<group>"; };
|
||||
58B5118B1A9E6BD600147676 /* RCTNetworkImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTNetworkImageView.h; sourceTree = "<group>"; };
|
||||
@@ -48,12 +57,18 @@
|
||||
58B511541A9E6B3D00147676 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1304D5B01AA8C50D0002E2BE /* RCTGIFImage.h */,
|
||||
1304D5B11AA8C50D0002E2BE /* RCTGIFImage.m */,
|
||||
58B511891A9E6BD600147676 /* RCTImageDownloader.h */,
|
||||
58B5118A1A9E6BD600147676 /* RCTImageDownloader.m */,
|
||||
58B5118B1A9E6BD600147676 /* RCTNetworkImageView.h */,
|
||||
58B5118C1A9E6BD600147676 /* RCTNetworkImageView.m */,
|
||||
58B5118D1A9E6BD600147676 /* RCTNetworkImageViewManager.h */,
|
||||
58B5118E1A9E6BD600147676 /* RCTNetworkImageViewManager.m */,
|
||||
1304D5A71AA8C4A30002E2BE /* RCTStaticImage.h */,
|
||||
1304D5A81AA8C4A30002E2BE /* RCTStaticImage.m */,
|
||||
1304D5A91AA8C4A30002E2BE /* RCTStaticImageManager.h */,
|
||||
1304D5AA1AA8C4A30002E2BE /* RCTStaticImageManager.m */,
|
||||
58B5115E1A9E6B3D00147676 /* Products */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
@@ -61,7 +76,7 @@
|
||||
58B5115E1A9E6B3D00147676 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
58B5115D1A9E6B3D00147676 /* libRCTNetworkImage.a */,
|
||||
58B5115D1A9E6B3D00147676 /* libRCTImage.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -69,9 +84,9 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
58B5115C1A9E6B3D00147676 /* RCTNetworkImage */ = {
|
||||
58B5115C1A9E6B3D00147676 /* RCTImage */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTNetworkImage" */;
|
||||
buildConfigurationList = 58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTImage" */;
|
||||
buildPhases = (
|
||||
58B511591A9E6B3D00147676 /* Sources */,
|
||||
58B5115A1A9E6B3D00147676 /* Frameworks */,
|
||||
@@ -81,9 +96,9 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTNetworkImage;
|
||||
name = RCTImage;
|
||||
productName = RCTNetworkImage;
|
||||
productReference = 58B5115D1A9E6B3D00147676 /* libRCTNetworkImage.a */;
|
||||
productReference = 58B5115D1A9E6B3D00147676 /* libRCTImage.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
@@ -100,7 +115,7 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTNetworkImage" */;
|
||||
buildConfigurationList = 58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTImage" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
@@ -112,7 +127,7 @@
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
58B5115C1A9E6B3D00147676 /* RCTNetworkImage */,
|
||||
58B5115C1A9E6B3D00147676 /* RCTImage */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -124,7 +139,10 @@
|
||||
files = (
|
||||
58B5118F1A9E6BD600147676 /* RCTImageDownloader.m in Sources */,
|
||||
58B511911A9E6BD600147676 /* RCTNetworkImageViewManager.m in Sources */,
|
||||
1304D5AC1AA8C4A30002E2BE /* RCTStaticImageManager.m in Sources */,
|
||||
58B511901A9E6BD600147676 /* RCTNetworkImageView.m in Sources */,
|
||||
1304D5B21AA8C50D0002E2BE /* RCTGIFImage.m in Sources */,
|
||||
1304D5AB1AA8C4A30002E2BE /* RCTStaticImage.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -213,8 +231,12 @@
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/UIExplorer-gjaibsjtheitasdxdtcvxxqavkvy/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = RCTImage;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -227,8 +249,12 @@
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../../ReactKit/**",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/UIExplorer-gjaibsjtheitasdxdtcvxxqavkvy/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = RCTImage;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
@@ -236,7 +262,7 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTNetworkImage" */ = {
|
||||
58B511581A9E6B3D00147676 /* Build configuration list for PBXProject "RCTImage" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B5116F1A9E6B3D00147676 /* Debug */,
|
||||
@@ -245,7 +271,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTNetworkImage" */ = {
|
||||
58B511711A9E6B3D00147676 /* Build configuration list for PBXNativeTarget "RCTImage" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511721A9E6B3D00147676 /* Debug */,
|
||||
@@ -109,39 +109,37 @@ typedef void (^RCTCachedDataDownloadBlock)(BOOL cached, NSData *data, NSError *e
|
||||
|
||||
- (id)downloadImageForURL:(NSURL *)url size:(CGSize)size scale:(CGFloat)scale block:(RCTImageDownloadBlock)block
|
||||
{
|
||||
NSString *cacheKey = [self cacheKeyForURL:url];
|
||||
__weak RCTImageDownloader *weakSelf = self;
|
||||
return [self _downloadDataForURL:url block:^(BOOL cached, NSData *data, NSError *error) {
|
||||
if (!data) {
|
||||
return dispatch_async(dispatch_get_main_queue(), ^{
|
||||
block(nil, error);
|
||||
});
|
||||
}
|
||||
return [self downloadDataForURL:url block:^(NSData *data, NSError *error) {
|
||||
|
||||
UIImage *image = [UIImage imageWithData:data scale:scale];
|
||||
|
||||
if (image) {
|
||||
|
||||
// Resize (TODO: should we take aspect ratio into account?)
|
||||
CGSize imageSize = size;
|
||||
if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
|
||||
imageSize = image.size;
|
||||
} else {
|
||||
imageSize = (CGSize){
|
||||
MIN(size.width, image.size.width),
|
||||
MIN(size.height, image.size.height)
|
||||
};
|
||||
}
|
||||
|
||||
// Rescale image if required size is smaller
|
||||
CGFloat imageScale = scale;
|
||||
if (imageScale == 0 || imageScale > image.scale) {
|
||||
if (imageScale == 0 || imageScale < image.scale) {
|
||||
imageScale = image.scale;
|
||||
}
|
||||
|
||||
// Decompress image at required size
|
||||
UIGraphicsBeginImageContextWithOptions(imageSize, NO, imageScale);
|
||||
[image drawInRect:(CGRect){{0, 0}, imageSize}];
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
if (!cached) {
|
||||
RCTImageDownloader *strongSelf = weakSelf;
|
||||
[strongSelf->_cache setData:UIImagePNGRepresentation(image) forKey:cacheKey];
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should we cache the decompressed image?
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
block(image, nil);
|
||||
});
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
#import "RCTNetworkImageView.h"
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTGIFImage.h"
|
||||
#import "RCTImageDownloader.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTConvert.h"
|
||||
|
||||
@implementation RCTNetworkImageView
|
||||
{
|
||||
@@ -53,7 +54,7 @@
|
||||
if ([imageURL.pathExtension caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
|
||||
_downloadToken = [_imageDownloader downloadDataForURL:imageURL block:^(NSData *data, NSError *error) {
|
||||
if (data) {
|
||||
CAKeyframeAnimation *animation = [RCTConvert GIF:data];
|
||||
CAKeyframeAnimation *animation = RCTGIFImageWithData(data);
|
||||
CGImageRef firstFrame = (__bridge CGImageRef)animation.values.firstObject;
|
||||
self.layer.bounds = CGRectMake(0, 0, CGImageGetWidth(firstFrame), CGImageGetHeight(firstFrame));
|
||||
self.layer.contentsScale = 1.0;
|
||||
|
||||
@@ -23,4 +23,3 @@ RCT_REMAP_VIEW_PROPERTY(src, imageURL)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode)
|
||||
|
||||
@end
|
||||
|
||||
|
||||
10
Libraries/Image/RCTStaticImage.h
Normal file
10
Libraries/Image/RCTStaticImage.h
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface RCTStaticImage : UIImageView
|
||||
|
||||
@property (nonatomic, assign) UIEdgeInsets capInsets;
|
||||
@property (nonatomic, assign) UIImageRenderingMode renderingMode;
|
||||
|
||||
@end
|
||||
55
Libraries/Image/RCTStaticImage.m
Normal file
55
Libraries/Image/RCTStaticImage.m
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTStaticImage.h"
|
||||
|
||||
@implementation RCTStaticImage
|
||||
|
||||
- (void)_updateImage
|
||||
{
|
||||
UIImage *image = self.image;
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply rendering mode
|
||||
if (_renderingMode != image.renderingMode) {
|
||||
image = [image imageWithRenderingMode:_renderingMode];
|
||||
}
|
||||
|
||||
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
|
||||
image = [image resizableImageWithCapInsets:_capInsets resizingMode:UIImageResizingModeStretch];
|
||||
}
|
||||
|
||||
// Apply trilinear filtering to smooth out mis-sized images
|
||||
self.layer.minificationFilter = kCAFilterTrilinear;
|
||||
self.layer.magnificationFilter = kCAFilterTrilinear;
|
||||
|
||||
super.image = image;
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image
|
||||
{
|
||||
if (image != super.image) {
|
||||
super.image = image;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setCapInsets:(UIEdgeInsets)capInsets
|
||||
{
|
||||
if (!UIEdgeInsetsEqualToEdgeInsets(_capInsets, capInsets)) {
|
||||
_capInsets = capInsets;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRenderingMode:(UIImageRenderingMode)renderingMode
|
||||
{
|
||||
if (_renderingMode != renderingMode) {
|
||||
_renderingMode = renderingMode;
|
||||
[self _updateImage];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
7
Libraries/Image/RCTStaticImageManager.h
Normal file
7
Libraries/Image/RCTStaticImageManager.h
Normal file
@@ -0,0 +1,7 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTViewManager.h"
|
||||
|
||||
@interface RCTStaticImageManager : RCTViewManager
|
||||
|
||||
@end
|
||||
43
Libraries/Image/RCTStaticImageManager.m
Normal file
43
Libraries/Image/RCTStaticImageManager.m
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#import "RCTStaticImageManager.h"
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTGIFImage.h"
|
||||
#import "RCTStaticImage.h"
|
||||
|
||||
@implementation RCTStaticImageManager
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [[RCTStaticImage alloc] init];
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(capInsets)
|
||||
RCT_REMAP_VIEW_PROPERTY(resizeMode, contentMode)
|
||||
RCT_CUSTOM_VIEW_PROPERTY(src, RCTStaticImage *)
|
||||
{
|
||||
if (json) {
|
||||
if ([[[json description] pathExtension] caseInsensitiveCompare:@"gif"] == NSOrderedSame) {
|
||||
[view.layer addAnimation:RCTGIFImageWithFileURL([RCTConvert NSURL:json]) forKey:@"contents"];
|
||||
} else {
|
||||
view.image = [RCTConvert UIImage:json];
|
||||
}
|
||||
} else {
|
||||
view.image = defaultView.image;
|
||||
}
|
||||
}
|
||||
RCT_CUSTOM_VIEW_PROPERTY(tintColor, RCTStaticImage *)
|
||||
{
|
||||
if (json) {
|
||||
view.renderingMode = UIImageRenderingModeAlwaysTemplate;
|
||||
view.tintColor = [RCTConvert UIColor:json];
|
||||
} else {
|
||||
view.renderingMode = defaultView.renderingMode;
|
||||
view.tintColor = defaultView.tintColor;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -23,7 +23,7 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
58B511DB1A9E6C8500147676 /* libRCTDataManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTDataManager.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
58B511DB1A9E6C8500147676 /* libRCTNetwork.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTNetwork.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
58B512061A9E6CE300147676 /* RCTDataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTDataManager.h; sourceTree = "<group>"; };
|
||||
58B512071A9E6CE300147676 /* RCTDataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDataManager.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@@ -51,7 +51,7 @@
|
||||
58B511DC1A9E6C8500147676 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
58B511DB1A9E6C8500147676 /* libRCTDataManager.a */,
|
||||
58B511DB1A9E6C8500147676 /* libRCTNetwork.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -59,9 +59,9 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
58B511DA1A9E6C8500147676 /* RCTDataManager */ = {
|
||||
58B511DA1A9E6C8500147676 /* RCTNetwork */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTDataManager" */;
|
||||
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTNetwork" */;
|
||||
buildPhases = (
|
||||
58B511D71A9E6C8500147676 /* Sources */,
|
||||
58B511D81A9E6C8500147676 /* Frameworks */,
|
||||
@@ -71,9 +71,9 @@
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = RCTDataManager;
|
||||
name = RCTNetwork;
|
||||
productName = RCTDataManager;
|
||||
productReference = 58B511DB1A9E6C8500147676 /* libRCTDataManager.a */;
|
||||
productReference = 58B511DB1A9E6C8500147676 /* libRCTNetwork.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
@@ -90,7 +90,7 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTDataManager" */;
|
||||
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTNetwork" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
@@ -102,7 +102,7 @@
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
58B511DA1A9E6C8500147676 /* RCTDataManager */,
|
||||
58B511DA1A9E6C8500147676 /* RCTNetwork */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -206,7 +206,7 @@
|
||||
"/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = RCTNetwork;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -224,7 +224,7 @@
|
||||
"/Users/nicklockwood/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/ReactKit/build/Debug-iphoneos",
|
||||
);
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PRODUCT_NAME = RCTNetwork;
|
||||
SKIP_INSTALL = YES;
|
||||
};
|
||||
name = Release;
|
||||
@@ -232,7 +232,7 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTDataManager" */ = {
|
||||
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTNetwork" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511ED1A9E6C8500147676 /* Debug */,
|
||||
@@ -241,7 +241,7 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTDataManager" */ = {
|
||||
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTNetwork" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
58B511F01A9E6C8500147676 /* Debug */,
|
||||
Reference in New Issue
Block a user