C5ZONE
CHÀO MỪNG BẠN ĐÃ GHÉ THĂM DIỄN ĐÀN C5Zone


Bạn nên đăng nhập hoặc đăng ký thì mới xem được những nội dung chính của DIỄN ĐÀN. Việc đăng nhập hoặc đăng ký làm thành viên không tốn phí gì đâu. bạn yên tâm.
Bạn cũng có thể cứ làm khách vẫn xem được một phần nội dung của Diễn đàn, nhưng bị nhiều hạn chế hạn chế ở các chuyên mục như: không xem được ảnh, không nhìn thấy link ...

< /form>< /div>< /div>
C5ZONE
CHÀO MỪNG BẠN ĐÃ GHÉ THĂM DIỄN ĐÀN C5Zone


Bạn nên đăng nhập hoặc đăng ký thì mới xem được những nội dung chính của DIỄN ĐÀN. Việc đăng nhập hoặc đăng ký làm thành viên không tốn phí gì đâu. bạn yên tâm.
Bạn cũng có thể cứ làm khách vẫn xem được một phần nội dung của Diễn đàn, nhưng bị nhiều hạn chế hạn chế ở các chuyên mục như: không xem được ảnh, không nhìn thấy link ...

< /form>< /div>< /div>
C5ZONELog in

We Share


Tạo animation đơn giản cho React Native ScrollView


[size=15]Ở bài viết trước, mình có chia sẻ cách sử dụng LayoutAnimation để tạo hiệu ứng cho ứng dụng React Native. Bài viết này mình chia sẻ một tip đặc biệt tạo Animation dành riêng cho React Native ScrollView.


Thực ra có rất nhiều cách để tạo animation cho ScrollView, bài viết này mình sẽ hướng dẫn các bạn sử dụng Animated API để tạo animation rất đơn giản mà hiệu quả.

Đây là kết quả cuối cùng

[/size]

Topics tagged under d3d3d3 on C5ZONE Giphy


Giải thích qua về thuật toán tạo animation

Ý tưởng là để tạo header có thể đè lên scrollview đó là sử dụng position: ‘absolutevà thiết lập margin top của scrollview một khoảng đúng bằng chiều cao của phần header. Sau đó, chúng ta sẽ tạo animation cho chiều cao header dùng ScrollView scroll position.

Tiến hành code

Đầu tiên là phải được một ScrollView cùng với dữ liệu để phục vụ tạo hiệu ứng ở bước sau:

  • [size=23]import React, {Component} from 'react';[/size]

  • [size=23]import {[/size]

  • [size=23] Animated,[/size]

  • [size=23] Image,[/size]

  • [size=23] ScrollView,[/size]

  • [size=23] StyleSheet,[/size]

  • [size=23] Text,[/size]

  • [size=23] View,[/size]

  • [size=23]} from 'react-native';[/size]


  • [size=23]export default class ScrollableHeader extends Component {[/size]


  • [size=23] _renderScrollViewContent() {[/size]

  • [size=23] const data = Array.from({length: 30});[/size]

  • [size=23] return ([/size]

  • [size=23] <View style={styles.scrollViewContent}>[/size]

  • [size=23] {data.map((_, i) =>[/size]

  • [size=23] <View key={i} style={styles.row}>[/size]

  • [size=23] <Text>{i}</Text>[/size]

  • [size=23] </View>[/size]

  • [size=23] )}[/size]

  • [size=23] </View>[/size]

  • [size=23] );[/size]

  • [size=23] }[/size]


  • [size=23] render() {[/size]

  • [size=23] return ([/size]

  • [size=23] <View style={styles.fill}>[/size]

  • [size=23] <ScrollView[/size]

  • [size=23] style={styles.fill}[/size]

  • [size=23] >[/size]

  • [size=23] {this._renderScrollViewContent()}[/size]

  • [size=23] </ScrollView>[/size]

  • [size=23] </View>[/size]

  • [size=23] );[/size]

  • [size=23] }[/size]

  • [size=23]}[/size]


  • [size=23]const styles = StyleSheet.create({[/size]

  • [size=23] fill: {[/size]

  • [size=23] flex: 1,[/size]

  • [size=23] },[/size]

  • [size=23] row: {[/size]

  • [size=23] height: 40,[/size]

  • [size=23] margin: 16,[/size]

  • [size=23] backgroundColor: '[You must be registered and logged in to see this link.]',[/size]

  • [size=23] alignItems: 'center',[/size]

  • [size=23] justifyContent: 'center',[/size]

  • [size=23] },[/size]

  • [size=23]});[/size]



Tiếp theo, chúng ta cần tạo header View và thêm margin cho phần content của ScrollView để phần content không nằm dưới header. Chúng ta vẫn thêm title cho phần header như bình thường.
Hãy thêm View vào sau ScrollView. Mục đích là để sử dụng Animated.View để tạo animation

  • [size=23]...[/size]

  • [size=23]<ScrollView>[/size]

  • [size=23] ...[/size]

  • [size=23]</ScrollView>[/size]

  • [size=23]<Animated.View style={styles.header}>[/size]

  • [size=23] <View style={styles.bar}>[/size]

  • [size=23] <Text style={styles.title}>Title</Text>[/size]

  • [size=23] </View>[/size]

  • [size=23]</Animated.View>[/size]

  • [size=23]...[/size]



Còn đây là styles:

  • [size=23]...[/size]

  • [size=23]header: {[/size]

  • [size=23] position: 'absolute',[/size]

  • [size=23] top: 0,[/size]

  • [size=23] left: 0,[/size]

  • [size=23] right: 0,[/size]

  • [size=23] backgroundColor: '[You must be registered and logged in to see this link.]',[/size]

  • [size=23] overflow: 'hidden',[/size]

  • [size=23]},[/size]

  • [size=23]bar: {[/size]

  • [size=23] marginTop: 28,[/size]

  • [size=23] height: 32,[/size]

  • [size=23] alignItems: 'center',[/size]

  • [size=23] justifyContent: 'center',[/size]

  • [size=23]},[/size]

  • [size=23]title: {[/size]

  • [size=23] backgroundColor: 'transparent',[/size]

  • [size=23] color: 'white',[/size]

  • [size=23] fontSize: 18,[/size]

  • [size=23]},[/size]

  • [size=23]scrollViewContent: {[/size]

  • [size=23] marginTop: HEADER_MAX_HEIGHT,[/size]

  • [size=23]},[/size]

  • [size=23]...[/size]



Chúng ta vẫn sẽ định nghĩa một số giá trị hằng số cho các kích thước header sẽ được sử dụng cho việc nội suy giá trị vị trí trong việc cuộn (scroll).
Chúng ta định nghĩa một số constant về kích thước cho header, mục đích để phục vụ việc interpolate các position item khi scroll.

  • [size=23]const HEADER_MAX_HEIGHT = 200;[/size]

  • [size=23]const HEADER_MIN_HEIGHT = 60;[/size]

  • [size=23]const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT — HEADER_MIN_HEIGHT;[/size]



Tiền hành chạy thử thì chúng ta sẽ được giao diện như bên dưới:
Topics tagged under d3d3d3 on C5ZONE React-native-scrollview-va-cach-tao-animation-rat-don-gian-2

Implement phần quan trọng nhất: Animation

React Native có những API tạo animation rất mạnh mẽ, nó cho phép tạo hiệu ứng một giá trị nhưng cũng đồng thời gắn giá trị của nó vào một sự kiện(event).
Trong bài tutorial này, chúng ta sẽ gắn một giá trị động (animated value) vào Y scroll position  của ScrollView.
Để làm điều đó, mình sử dụng Animated.event với ScrollView onScroll props. Đại khái như bên dưới

  • [size=23]...[/size]


  • [size=23]constructor(props) {[/size]

  • [size=23] super(props);[/size]


  • [size=23] this.state = {[/size]

  • [size=23] scrollY: new Animated.Value(0),[/size]

  • [size=23] };[/size]

  • [size=23]}[/size]


  • [size=23]...[/size]

  • [size=23] [/size]

  • [size=23]render() {[/size]

  • [size=23] const headerHeight = this.state.scrollY.interpolate({[/size]

  • [size=23] inputRange: [0, HEADER_SCROLL_DISTANCE],[/size]

  • [size=23] outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],[/size]

  • [size=23] extrapolate: 'clamp',[/size]

  • [size=23] });[/size]

  • [size=23] [/size]

  • [size=23] ...[/size]


  • [size=23] <ScrollView[/size]

  • [size=23] style={styles.fill}[/size]

  • [size=23] scrollEventThrottle={16}[/size]

  • [size=23] onScroll={Animated.event([/size]

  • [size=23] [{nativeEvent: {contentOffset: {y: this.state.scrollY}}}][/size]

  • [size=23] )}[/size]

  • [size=23] >[/size]

  • [size=23] ...[/size]

  • [size=23] </ScrollView>[/size]

  • [size=23] <Animated.View style={[styles.header, {height: headerHeight}]}>[/size]

  • [size=23] ...[/size]

  • [size=23] </Animated.View>[/size]

  • [size=23] ...[/size]

  • [size=23]}[/size]



Mình giải thích qua một chút đoạn code ở trên:
Đầu tiên, chúng ta tạo ra Animated.Value, đó là một giá trị mà có thể tạo hiệu ứng animation bằng cách sử dụng API Animated.
Sau đó, chúng bind animated value vào ScrollView scroll position. Đơn giản là chúng ta sử dụng Animated.event với việc ánh xạ tới thuộc tính của đối tượng event mà có thể bind giá trị animated value . Trong trường hợp này, nó chính là .nativeEvent.contentOffset.y.
Sau đó, mình sử dụng hàm interpolate giá trị Animated.Value để ánh xạ scroll position với chiều cao header mong muốn. Điều mình muốn là khi vị trí cuộn ở 0, header ở mức HEADER_MAX_HEIGHT và khi vị trí cuộn đã di chuyển đến chênh lệch giữa HEADER_MAX_HEIGHT và HEADER_MIN_HEIGHT, header ở mức HEADER_MIN_HEIGHT.
Cuối cùng chúng ta chỉ cần thiết lập chiều cao với giá trị animated cho header view.
Các bạn để ý thuộc tính scrollEventThrottle, mình đang để là 16 để các event được gửi thường xuyên hơn và để animation được mượt mà hơn.
Khi mà header di chuyển với scroll position và sử dụng kỹ thuật tương tự, chúng ta có thể tạo thêm nhiều hiệu ứng khác cho header trong khi người dùng scroll.

  • Dành riêng cho bạn: React Native – Phân biệt Props và State cực kỳ đơn giản và dễ hiểu


Sáng tạo với nhiều hiệu ứng hơn

Topics tagged under d3d3d3 on C5ZONE React-native-scrollview-va-cach-tao-animation-rat-don-gian-3

Mình sẽ sáng tạo một chút nhé
Để header bớt nhàm chán, mình sẽ thêm hình ảnh một con mèo với hiệu ứng parallax. Để làm điều này chúng ta hãy thêm hai giá trị: interpolated animated và một Image component

  • [size=23]...[/size]


  • [size=23]const imageOpacity = this.state.scrollY.interpolate({[/size]

  • [size=23] inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],[/size]

  • [size=23] outputRange: [1, 1, 0],[/size]

  • [size=23] extrapolate: 'clamp',[/size]

  • [size=23]});[/size]

  • [size=23]const imageTranslate = this.state.scrollY.interpolate({[/size]

  • [size=23] inputRange: [0, HEADER_SCROLL_DISTANCE],[/size]

  • [size=23] outputRange: [0, -50],[/size]

  • [size=23] extrapolate: 'clamp',[/size]

  • [size=23]});[/size]


  • [size=23]...[/size]


  • [size=23]<ScrollView>[/size]

  • [size=23] ...[/size]

  • [size=23]</ScrollView>[/size]

  • [size=23]<Animated.View style={[styles.header, {height: headerHeight}]}>[/size]

  • [size=23] <Animated.Image[/size]

  • [size=23] style={[[/size]

  • [size=23] styles.backgroundImage,[/size]

  • [size=23] {opacity: imageOpacity, transform: [{translateY: imageTranslate}]},[/size]

  • [size=23] ]}[/size]

  • [size=23] source={require('./images/cat.jpg')}[/size]

  • [size=23] />[/size]

  • [size=23] <Animated.View>[/size]

  • [size=23] ...[/size]

  • [size=23] </Animated.View>[/size]

  • [size=23]</Animated.View>[/size]


  • [size=23]...[/size]


  • [size=23]backgroundImage: {[/size]

  • [size=23] position: 'absolute',[/size]

  • [size=23] top: 0,[/size]

  • [size=23] left: 0,[/size]

  • [size=23] right: 0,[/size]

  • [size=23] width: null,[/size]

  • [size=23] height: HEADER_MAX_HEIGHT,[/size]

  • [size=23] resizeMode: 'cover',[/size]

  • [size=23]},[/size]

  • [size=23] [/size]

  • [size=23]...[/size]



Bài tập về nhà
Phần dành cho các bạn: Thêm hiệu ứng mở rộng title khi người dùng scroll xuống dưới. Các bạn thử code xem nhé, nếu có khó khăn thì comment bên dưới để mọi người cùng giúp đỡ

Tổng kết

API Animated giúp cho việc tạo animation phức tạp trở nên dễ dàng hơn bao giờ hết. Nó còn cho phép giữ state vô cùng đơn giản. Tất cả đều dựa trên một value,và animation phức tạp đều được xử lý trong hàm render với interpolations.
[size=16] Download full source code[/size]
Qua bài viết này chúng ta đã hiểu hơn về React Native rồi đấy. Với API Animated, ứng dụng của bạn sẽ đẹp hơn rất nhiều. Mình rất hi vọng bài viết sẽ giúp ích cho các bạn, đừng quên comment ủng hộ mình nhé