RN7_實戰(3)
參考:http://reactnative.cn/docs/0.41/images.html#content(進階指南部分)
只需把圖片文件放在代碼文件夾中某處,然后像下面這樣去引用它。
<Image source={require('./my-icon.png')}/>
是哪個組件引用了這個圖片,Packager就會去這個組件所在的文件夾下查找my-icon.png。
<Image source={{uri:'app_icon'}}style={{width:40,height:40}} />
使用已經打包到App中的圖片資源。
<Imagesource={{uri: 'https://facebook.github.io/react/img/logo_og.png'}}
style={{width:400,height:400}} />
注意:
在引入網絡圖片的時候,你需要手動指定圖片的尺寸!
原因:
瀏覽器中,如果你不給圖片指定尺寸,那么瀏覽器會首先渲染一個0x0大小的元素占位,然后下載圖片,在下載完成后再基于正確的尺寸來渲染圖片。
已經打包好的應用資源文件中讀取圖片(使用require('image!x')語法)則無需指定尺寸,因為它們的尺寸在加載時就可以立刻知道。
return (
<Imagesource={...}>
<Text>Inside</Text>
</Image>
);
只需簡單地創建一個<Image>組件,然后把需要背景圖的子組件嵌入其中即可。
classMyButtonextendsComponent{
_onPRessButton() {
console.log("Youtapped the button!");
}
render() {
return (
<TouchableHighlightonPress={this._onPressButton}>
<Text>Button</Text>
</TouchableHighlight>
);
}
}
使用onLongPress屬性來實現。
設置maximumZoomScale和minimumZoomScale屬性即可以使用戶能夠縮放其中的內容
摸響應系統可以使組件在不關心父組件或子組件的前提下自行處理觸摸交互。具體的實現在ResponderEventPlugin.js文件中。
響應者:一個View只要實現了正確的協商方法,就可以成為觸摸事件的響應者:
l View.props.onStartShouldSetResponder: (evt) => true, - 在用戶開始觸摸的時候(手指剛剛接觸屏幕的瞬間),是否愿意成為響應者?
l View.props.onMoveShouldSetResponder: (evt) => true, - 如果View不是響應者,那么在每一個觸摸點開始移動(沒有停下也沒有離開屏幕)時再詢問一次:是否愿意響應觸摸交互呢?
如果View返回true,并開始嘗試成為響應者。
l View.props.onResponderMove: (evt) => {} - 用戶正在屏幕上移動手指時(沒有停下也沒有離開屏幕)。
l View.props.onResponderRelease: (evt) => {} - 觸摸操作結束時觸發,比如"touchUp"(手指抬起離開屏幕)。
l View.props.onResponderTerminationRequest: (evt) => true - 有其他組件請求接替響應者,當前的View是否“放權”?返回true的話則釋放響應者權力。
l View.props.onResponderTerminate: (evt) => {} - 響應者權力已經交出。這可能是由于其他View通過onResponderTerminationRequest請求的,也可能是由操作系統強制奪權(比如iOS上的控制中心或是通知中心)。
nativeEvent:
l changedTouches - 在上一次事件之后,所有發生變化的觸摸事件的數組集合(即上一次事件后,所有移動過的觸摸點)
l identifier - 觸摸點的ID
l locationX - 觸摸點相對于父元素的橫坐標
l locationY - 觸摸點相對于父元素的縱坐標
l pageX - 觸摸點相對于根元素的橫坐標
l pageY - 觸摸點相對于根元素的縱坐標
l target - 觸摸點所在的元素ID
l timestamp - 觸摸事件的時間戳,可用于移動速度的計算
l touches - 當前屏幕上的所有觸摸點的集合
onStartShouldSetResponder與onMoveShouldSetResponder是以冒泡的形式調用的,即嵌套最深的節點最先調用。這意味著當多個View同時在*ShouldSetResponder中返回true時,最底層的View將優先“奪權”。
如果某個父View想要在觸摸操作開始時阻止子組件成為響應者,那就應該處理onStartShouldSetResponderCapture事件并返回true值。
l View.props.onStartShouldSetResponderCapture:(evt) => true,
l View.props.onMoveShouldSetResponderCapture:(evt) => true,
class Playground extends React.Component {
constructor(props: any) {
super(props);
this.state= {
bounceValue:new Animated.Value(0),
};
}
render(): ReactElement {
return(
<Animated.Image // 可選的基本組件類型: Image, Text, View
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
style={{
flex: 1,
transform:[ // `transform`是一個有序數組(動畫按順序執行)
{scale: this.state.bounceValue}, // 將`bounceValue`賦值給 `scale`
]
}}
/>
);
}
componentDidMount() {
this.state.bounceValue.setValue(1.5); // 設置一個較大的初始值
Animated.spring( // 可選的基本動畫類型:spring, decay, timing
this.state.bounceValue, // 將`bounceValue`值動畫化
{
toValue: 0.8, // 將其值以動畫的形式改到一個較小值
friction: 1, // Bouncier spring
}
).start(); // 開始執行動畫
}
}
分析:
1、bounceValue在構造函數中初始化為state的一部分,然后和圖片的縮放比例進行綁定。在動畫執行的背后,其數值會被不斷的計算并用于設置縮放比例。
2、當組件剛剛掛載的時候,縮放比例被設置到1.5。然后緊跟著在bounceValue上執行了一個彈跳動畫(spring),會逐幀刷新數值,并同步更新所有依賴本數值的綁定(在這個例子里,就是圖片的縮放比例)。
兩個值類型:Value用于單個的值,而ValueXY用于向量值
三種動畫類型:spring,decay,還有timing
三種組件類型:View,Text和Image
三種動畫:三種動畫類型可以用來創建幾乎任何你需要的動畫曲線,因為它們每一個都可以被自定義。
spring: 基礎的單次彈跳物理模型,符合Origami設計標準
l friction: 摩擦力,默認為7.
l tension: 張力,默認40。
decay: 以一個初始速度開始并且逐漸減慢停止。
l velocity: 起始速度,必填參數。
l deceleration:速度衰減比例,默認為0.997。
timing: 從時間范圍映射到漸變的值。
l duration: 動畫持續的時間(單位是毫秒),默認為500。
l easing:一個用于定義曲線的漸變函數。閱讀Easing模塊可以找到許多預定義的函數。
l delay: 在一段時間之后開始動畫(單位是毫秒),默認為0。
動畫可以通過調用start方法來開始。start接受一個回調函數,當動畫結束的時候會調用此回調函數。如果動畫是因為正常播放完成而結束的,回調函數被調用時的參數為{finished: true},但若動畫是在結束之前被調用了stop而結束(可能是被一個手勢或者其它的動畫打斷),它會收到參數{finished: false}。
多個動畫可以通過parallel(同時執行)、sequence(順序執行)、stagger和delay來組合使用。它們中的每一個都接受一個要執行的動畫數組,并且自動在適當的時候調用start/stop。
Eg:
Animated.sequence([ //首先執行decay動畫,結束后同時執行spring和twirl動畫
Animated.decay(position, { //滑行一段距離后停止
velocity: {x: gestureState.vx,y:gestureState.vy},//根據用戶的手勢設置速度
deceleration: 0.997,
}),
Animated.parallel([ //在decay之后并行執行:
Animated.spring(position, {
toValue: {x:0,y:0} //返回到起始點開始
}),
Animated.timing(twirl, { //同時開始旋轉
toValue: 360,
}),
]),
]).start(); //執行這一整套動畫序列
插值函數interpolate, 它可以接受一個輸入區間,然后將其映射到另一個的輸出區間。
Eg:
value.interpolate({
inputRange: [0,1],
outputRange: [0,100],
});
從0-1區間到0-100區間的映射。
動畫中所設的值還可以通過跟蹤別的值得到。你只要把toValue設置成另一個動態值而不是一個普通數字就行了。
可以使用插值來進行組合:
Eg:
Animated.spring(follower, {toValue:leader}).start();
Animated.timing(opacity, {
toValue:pan.x.interpolate({
inputRange: [0,300],
outputRange: [1,0],
}),
}).start();
l setTimeout, clearTimeout
l setInterval, clearInterval
l setImmediate, clearImmediate
l requestAnimationFrame, cancelAnimationFrame
1. requestAnimationFrame(): 用來執行在一段時間內控制視圖動畫的代碼
2. setImmediate/setTimeout/setInterval(): 在稍后執行代碼。注意這有可能會延遲當前正在進行的動畫。
3. runAfterInteractions(): 在稍后執行代碼,不會延遲當前進行的動畫。
TimerMixin很多React Native應用發生致命錯誤(閃退)是與計時器有關。具體來說,是在某個組件被卸載(unmount)之后,計時器卻仍然被激活。為了解決這個問題,我們引入了TimerMixin。如果你在組件中引入TimerMixin,就可以把你原本的setTimeout(fn, 500)改為this.setTimeout(fn, 500)(只需要在前面加上this.),然后當你的組件卸載時,所有的計時器事件也會被正確的清除。
Eg:
varTimerMixin =require('react-timer-mixin');
varComponent = React.createClass({
mixins: [TimerMixin],
componentDidMount:function(){
this.setTimeout(
() => {console.log('這樣我就不會導致內存泄露!'); },
500
);
}
});
這里要銘記:在unmount組件時清除(clearTimeout/clearInterval)所有用到的定時器!
Eg:
import React,{
Component
} from'react';
exportdefaultclassHelloextendsComponent{
componentDidMount() {
this.timer =setTimeout(
() => {console.log('把一個定時器的引用掛在this上'); },
500
);
}
componentWillUnmount() {
//如果存在this.timer,則使用clearTimeout清空。
//如果你使用多個timer,那么用多個變量,或者用個數組來保存引用,然后逐個clear
this.timer&& clearTimeout(this.timer);
}
};
寫RN1到現在,感覺RN好弱雞。寫的動畫卡的不行,navigation翻頁也卡,知道RN里面僅僅是JS的單線程在運行,卡也沒辦法。
鑒于目前是什么都沒接觸過的新手,感覺這十幾天的學習大概RN的代碼是會看一些了?;镜臇|西都大概了解一些,對于真正去做項目感覺還很遠啊!悲傷~
之前寫的東西,都會復制粘貼到demo工程中去看看效果。一些報錯也大概了解。但是僅僅是了解的階段。開發環境也熟悉了一些。同事用inteliJ可以建RN項目,感覺好棒,但是我還是默默用cmd建好了。
總之這條路真是走的惡心。僅僅對RN的開發有些熟悉(其實似乎還是什么都不太會,但是大概能看懂代碼了)。雖然有android開發基礎(好歹android開發我還是6的),但是吃起RN這坨屎還是比較費力的。Navigation我都沒有看懂~接下來官方文檔感覺對我的幫助不是很大了。我要去找一些實際開發的教學視頻!接下來就圍繞教學視頻來寫學習筆記了~
新聞熱點
疑難解答