Skip to content

Commit 9fbb44b

Browse files
committed
feat(Image): add support for local image
1 parent 53a406d commit 9fbb44b

File tree

6 files changed

+65
-29
lines changed

6 files changed

+65
-29
lines changed

example/src/assets/logo.png

8.63 KB
Loading

example/src/views/FullFormExample.tsx

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import {SwiftUI} from '@mgcrea/react-native-swiftui/src';
22
import {useState, type FunctionComponent} from 'react';
3-
import {View} from 'react-native';
3+
import {Image, View} from 'react-native';
4+
import logoImage from '../assets/logo.png';
5+
6+
console.log({
7+
logoImage,
8+
resolvedLogoImage: Image.resolveAssetSource(logoImage),
9+
});
410

511
export const FullFormExample: FunctionComponent = () => {
612
return (
@@ -166,20 +172,31 @@ const RectangleSection: FunctionComponent = () => {
166172
};
167173

168174
const ImageSection: FunctionComponent = () => {
169-
const [color, setColor] = useState('blue');
175+
const [icon, setIcon] = useState('iphone');
170176

171177
return (
172-
<SwiftUI.Section header="Rectangle Example">
173-
<SwiftUI.Image
174-
name="star.fill"
175-
isSystemImage={true}
176-
tintColor="#FF0000"
177-
style={{width: 50, height: 50}}
178-
/>
179-
178+
<SwiftUI.Section header="Image Example">
179+
<SwiftUI.HStack>
180+
<SwiftUI.Image
181+
source={logoImage}
182+
resizeMode="contain"
183+
style={{
184+
width: 128,
185+
height: 128,
186+
borderWidth: 1,
187+
borderColor: 'blue',
188+
borderRadius: 64,
189+
}}
190+
/>
191+
<SwiftUI.Image
192+
name={`system:${icon}`}
193+
// tintColor="#FF0000"
194+
style={{width: 128, height: 128, fontSize: 64, color: 'blue'}}
195+
/>
196+
</SwiftUI.HStack>
180197
<SwiftUI.Button
181-
title={`Change flag to ${color === 'blue' ? 'Italy' : 'France'}`}
182-
onPress={() => setColor(color === 'blue' ? 'green' : 'blue')}
198+
title={`Change icon to ${icon === 'iphone' ? 'ipad' : 'iphone'}`}
199+
onPress={() => setIcon(icon === 'iphone' ? 'ipad' : 'iphone')}
183200
/>
184201
</SwiftUI.Section>
185202
);

ios/components/Image/ImageProps.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import SwiftUI
22

33
public final class ImageProps: ObservableObject, Decodable {
4-
@Published var name: String = ""
5-
@Published var isSystemImage: Bool = false
4+
@Published var name: String?
5+
@Published var sourceUri: String?
66
@Published var resizeMode: ImageResizeMode
77
@Published var tintColor: String?
88
@Published var style: StyleProps?
@@ -32,21 +32,21 @@ public final class ImageProps: ObservableObject, Decodable {
3232
}
3333

3434
enum CodingKeys: String, CodingKey {
35-
case name, isSystemImage, resizeMode, tintColor, style
35+
case name, sourceUri, isSystemImage, resizeMode, tintColor, style
3636
}
3737

3838
public required init(from decoder: Decoder) throws {
3939
let container = try decoder.container(keyedBy: CodingKeys.self)
40-
name = try container.decode(String.self, forKey: .name)
41-
isSystemImage = try container.decodeIfPresent(Bool.self, forKey: .isSystemImage) ?? false
40+
name = try container.decodeIfPresent(String.self, forKey: .name)
41+
sourceUri = try container.decodeIfPresent(String.self, forKey: .sourceUri)
4242
resizeMode = try ImageResizeMode(rawValue: container.decodeIfPresent(String.self, forKey: .resizeMode) ?? "") ?? .default
4343
tintColor = try container.decodeIfPresent(String.self, forKey: .tintColor)
4444
style = try container.decodeIfPresent(StyleProps.self, forKey: .style)
4545
}
4646

4747
public func merge(from other: ImageProps) {
4848
name = other.name
49-
isSystemImage = other.isSystemImage
49+
sourceUri = other.sourceUri
5050
resizeMode = other.resizeMode
5151
tintColor = other.tintColor
5252
style = other.style

ios/components/Image/ImageView.swift

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,24 @@ public struct ImageView: View {
44
@ObservedObject public var props: ImageProps
55

66
public var body: some View {
7-
let baseImage = props.isSystemImage ? Image(systemName: props.name) : Image(props.name)
7+
let image: Image
8+
if let sourceUri = props.sourceUri, // Check for URI-based image first
9+
let url = URL(string: sourceUri),
10+
let data = try? Data(contentsOf: url),
11+
let uiImage = UIImage(data: data)
12+
{
13+
image = Image(uiImage: uiImage) // Load from URI
14+
} else if let name = props.name { // Fall back to named image
15+
if name.hasPrefix("system:") {
16+
let systemName = String(name.dropFirst("system:".count))
17+
image = Image(systemName: systemName) // Load system image
18+
} else {
19+
image = Image(name) // Load named asset
20+
}
21+
} else {
22+
return AnyView(Text("No image source provided")) // Fallback if neither is set
23+
}
824
// let tintedImage = props.tintColor != nil ? image.foregroundColor(Color(hex: props.tintColor!)) : image
9-
return props.resizeMode.applyResizeMode(baseImage).foregroundStyle(Color.red).applyStyles(props.style)
25+
return AnyView(props.resizeMode.applyResizeMode(image).applyStyles(props.style))
1026
}
1127
}

ios/extensions/View+Styling.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,16 @@ extension View {
3434
}
3535

3636
private func applyTextStyles(_ style: StyleProps) -> some View {
37-
return applyIf(style.fontWeight != nil) { view in
37+
return applyIf(style.color != nil) { $0.foregroundStyle(style.color!) }
38+
.applyIf(style.font != nil) { $0.font(style.font!) }
39+
.applyIf(style.fontSize != nil) { $0.font(.system(size: style.fontSize!)) }
40+
.applyIf(style.fontWeight != nil) { view in
3841
if #available(iOS 16.0, *) {
3942
return AnyView(view.fontWeight(style.fontWeight!))
4043
} else {
4144
return AnyView(view)
4245
}
4346
}
44-
.applyIf(style.font != nil) { $0.font(style.font!) }
45-
.applyIf(style.fontSize != nil) { $0.font(.system(size: style.fontSize!)) }
4647
}
4748

4849
@ViewBuilder

src/components/Image.tsx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
1+
import { Image as BaseImage, type ImageSourcePropType } from "react-native";
12
import { useSwiftUINode } from "../hooks";
2-
import type { FunctionComponentWithId, NativeViewStyle } from "../types";
3+
import type { FunctionComponentWithId, NativeTextStyle } from "../types";
34

45
export type NativeImageProps = {
5-
name: string;
6-
isSystemImage?: boolean;
6+
name?: string;
7+
source?: ImageSourcePropType;
78
resizeMode?: "cover" | "contain" | "stretch" | "center";
89
tintColor?: string;
9-
style?: NativeViewStyle;
10+
style?: NativeTextStyle;
1011
};
1112

12-
export const Image: FunctionComponentWithId<NativeImageProps> = ({ ...props }) => {
13-
useSwiftUINode("Image", props);
13+
export const Image: FunctionComponentWithId<NativeImageProps> = ({ source, ...props }) => {
14+
const sourceUri = source ? BaseImage.resolveAssetSource(source).uri : undefined;
15+
useSwiftUINode("Image", { sourceUri, ...props });
1416
return null;
1517
};
1618

0 commit comments

Comments
 (0)