新建商品頁面-NewMerchandise
Icon 元件
由
react-native-vector-icons
提供
import Icon from 'react-native-vector-icons/FontAwesome'
...
<Icon name="plus" size={24} color='#ccc' />
name
該icon 顯示名稱,由網站上查詢而得 https://fontawesome.com/icons?d=gallerycolor
設定icon的顏色
Icon.Button 元件
實現點擊Icon 執行指定動作
borderRadius
activeOpacity
underlayColor
<Icon.Button borderRadius={0} onPress={this.addToCart} name="plus" size={56} />
為Icon.Button 加入文字
<Icon.Button color="#ccc" style={styles.commentAction} backgroundColor="transparent" name="thumbs-up" size={36} activeOpacity={0.7} onPress={this.onLike} > <Text style={styles.actionText}>給予賣家好評</Text> </Icon.Button>
使用AsyncStorage
儲存UI 的 local state,譬如說因表單過於複雜,防止UI state reset 或等資料消失因素,讓使用者必須重新輸入,造成不便
若存放的是物件,使用
JSON.stringify(object)
將其轉成字串取出時再用
JSON.parse
抓回AsyncStorage 底層是用資料庫的方式實現,所以會有寫檔與讀檔的等待時間,所以在
getItem
時必須使用await 等待讀檔完成由於setItem 並不想要知道存檔成功或失敗的結果,所以不使用await等待setItem結束
import { AsyncStorage } from 'react-native';
const STORE_KEY = 'NewMerchandise';
export default class Example extends Component {
async componentWillMount() {
const form = await AsyncStorage.getItem(STORE_KEY);
if (form) {
this.setState({
...this.state,
...JSON.parse(form)
});
}
}
composeStringForm = () => {
const { description, title, photos } = this.state;
return JSON.stringify({
description,
title,
photos
});
};
onTitleChange = (text) => {
this.setState(
{
title: text
},
() => {
AsyncStorage.setItem(STORE_KEY, this.composeStringForm());
}
);
};
}
實現上傳多張照的UI
自製PhotoItem component 並且設計是否顯示+號的Property
export default class PhotoItem extends Component {
static propTypes = {
displayAdd: PropTypes.bool,
onPress: PropTypes.func.isRequired
};
static defaultProps = {
displayAdd: false
};
....
}
利用
react-native-vector-icons
顯示加號
<TouchableOpacity
onPress={this.props.onPress}
style={[styles.defaultSize, styles.dashBorder, styles.itemContainer]}
>
{displayAdd && <Icon size={58} name="plus" />}
</TouchableOpacity>
當按下後將onPress delegate回 parent component (NewMerchandise) 去開啟相機
使用相機的key值來區分是該上傳的照片是在畫面三格中的哪一格
goMerchandiseCamera = (i) => {
const { photos } = this.state;
const isContainEmpty = photos[i].empty;
if (isContainEmpty) {
const onTakePicture = (key, uri) => {
const newPhotos = [...photos];
newPhotos[i].empty = false;
newPhotos[i].uri = uri;
this.setState({
photos: newPhotos
});
};
this.props.navigation.navigate('Camera', {
to: 'NewMerchandise',
key: i,
onTakePicture
});
}
};
使用TextInput 加自製Icon Button 實現簡易加入連結的功能
偵測使用者選擇的範圍
onSelectionChange
並記錄起來
onDescriptionSelectionChange = ({ nativeEvent }) => {
const { start, end } = nativeEvent.selection;
this.setState({
descriptionStart: start,
descriptionEnd: end
});
};
將選取的範圍在
onChangeText
中替換成<a href={連結網址}>{連結文字}</a>
來達到連結效果attachLink = () => { console.warn('attach link'); const { description, descriptionStart, descriptionEnd } = this.state; const selectionString = description.substring(descriptionStart, descriptionEnd); const ANCHOR_LINK = `<a href="http://www.google.com.tw">${selectionString}</a>`; this.setState({ description: description.replace(selectionString, ANCHOR_LINK) }); };
將TextInput 利用
ScrollView
包裹住,讓使用者可以輸入長篇的商品簡介(mutiline=true),並且只在輸入description 時跳出自製toolbar設置
multiline=true
讓使用者可以按下enter鍵進行換行
<ScrollView
ref={(ref) => {
this.descriptionScrollRef = ref;
}}>
<TextInput
onFocus={() => {
this.setState({
showToolBar: true
});
}}
onBlur={() => {
this.setState({
showToolBar: false
});
}}
multiline
placeholder="請輸入商品敘述"
value={this.state.description}
onChangeText={this.onDescriptionChange}
onSelectionChange={this.onDescriptionSelectionChange}
ref={(ref) => {
this.description = ref;
}}
/>
</ScrollView>
[錯誤更正]並不存在要使用scrollToEnd的情況,
若將整個版面以ScrollView 包裝起來則不用使用scrollToEnd,
因為版面的ScrollView 在TextInput增長的過程中,會往下進行scroll
{photos.map((photo, i) => ( { this.goMerchandiseCamera(i); }} displayAdd={photo.empty} uri={photo.uri} /> ))} { this.setState({ showToolBar: true }); }} onBlur={() => { this.setState({ showToolBar: false }); }} multiline placeholder="請輸入商品敘述" value={this.state.description} style={styles.description} onChangeText={this.onDescriptionChange} onSelectionChange={this.onDescriptionSelectionChange} ref={(ref) => { this.description = ref; }} />
Last updated
Was this helpful?