12/08/2018, 15:38

[React Native] Guide - Phần 2 - Animations Part 2

Animations Theo dõi các giá trị linh động Những giá trị của animation có thể theo dõi các giá trị khác. Chỉ cần cài đặt cho thuộc tính toValue của một animation tới một giá trị thay thế của một animation khác là một số. Ví dụ một animation "Chat Heads" giống như đã từng được sử dụng bởi ...

Animations

Theo dõi các giá trị linh động

Những giá trị của animation có thể theo dõi các giá trị khác. Chỉ cần cài đặt cho thuộc tính toValue của một animation tới một giá trị thay thế của một animation khác là một số. Ví dụ một animation "Chat Heads" giống như đã từng được sử dụng bởi chương trình Messager trên Android có thể được triển khai với phương thức spring() đính trên một giá trị animation khác, hoặc với timing() và một duration là 0 để ràng buộc việc theo dõi. Chúng ta có thể làm được điều này bằng các phép nội suy như ví dụ dưới đây:

Animated.spring(follower, {toValue: leader}).start();
Animated.timing(opacity, {
  toValue: pan.x.interpolate({
    inputRange: [0, 300],
    outputRange: [1, 0],
  }),
}).start();

Các giá trị leader và follower sẽ được triển khai bằng cách sử dụng Animated.ValueXY(), ValueXY được điều khiển đa phần là trên hệ tọa độ 2D ví dụ như quét hoặc kéo. Nó đơn giản là bao bọc những nội dung cơ bản của hai thể hiện Animated.Value và một vài phương thức hỗ trợ sẽ được gọi thông qua chúng, việc tạo ra ValueXY để có thể thay thế cho Value trong một vài trường hợp. Nó cho phép bạn theo dõi đồng cả hai giá trị x và y trong ví dụ ở bên trên.

Theo dõi các thao tác tương tác

Tương tác với màn gì, giống như thực hiện các hành động panning hay scrolling, và các sự kiện khác nữa có thể mapping trực tiếp với các giá trị của animation bằng cách sử dụng Animated.event. Đố hoàn toàn là cấu trúc map để các giá trị có thể thay đổi chính xác theo từng đối tượng của các sự kiện. Ở level cao nhất đố là một mảng cho phép mapping rất nhiều các tham số đầu vào, và đó là những mảng có chứa các đối tượng cần thiêt.

Để ví dụ cho việc này, khi làm việc với scolling theo chiều ngang, bạn có thể thực hiện bằng cách yêu cầu để map event.nativeEvent.contentOffset.x tới scrollX (chính là một Animated.Value).

onScroll={Animated.event(
   // scrollX = e.nativeEvent.contentOffset.x
   [{ nativeEvent: {
        contentOffset: {
          x: scrollX
        }
      }
    }]
 )}

Khi sử dụng PanResponder bạn có thể sử dụng những cài đặt đi theo chính xác theo vị trí x và y được lấy ra từ gestureState.dx và gestureState.dy. Chúng ta sử dụng một null ở vị trí đầu tiên của mảng, và chúng ta chỉ để ý vào tham số thức hai để điều khiển các PanResponder, ở đó chính là gestureState.

onPanResponderMove={Animated.event(
  [null, // ignore the native event
  // extract dx and dy from gestureState
  // like 'pan.x = gestureState.dx, pan.y = gestureState.dy'
  {dx: pan.x, dy: pan.y}
])}

Trả lại giá trị hiện tại của animation

Bạn có thể chú ý rằng không có cách rõ ràng để đọc giá trị hiện tại của animation. Đây là bởi vì giá trị có thể chỉ được biết trong quá trình ứng dụng chạy. Nếu bạn cần để chạy JavaScript trong việc trả về giá trị hiện tại, có hai cách:

  • spring.stopAnimation(callback) sẽ dừng animation và đưa vào callback với giá trị cuối cùng. Điều này hữu dụng khi muốn tạo ra các tương tác di chuyển.
  • spring.addListener(callback) sẽ đưa vào callback đồng bộ trong khi animation đang chạy, cung cấp giá trị gần nhất. Điều này hữu dụng để để lắng nghe khi có các trạng thái thay đổi, ví dụ như việc di chuyển một đối tượng để có một giá trị mới giống như người dùng kéo nó. Bởi vì các trạng thái có sự thay đổi lớn này có đội trễ so với các cử chỉ liên tục như panning cần chạy với tốc độ 60fps.

Animated được thiết kế để liên kết đầy đủ để chạy animation có thể được chạy với hiệu năng cao, hoàn toàn độc lập của sự kiện lặp với JavaScript thông thường. Điều này là ảnh hưởng từ API, thế nên để giữ những hiểu biết đã có khi đây là một phần của hệ thống bất đồng bộ. Chuyển sang Animated.Value.addListener như một cahcs để làm biệc với những cách thức để giới hạn. nhưng không nên sử dụng nó nhiều vì nó sẽ không có hiệu năng tốt trong tương lai.

Sử dụng Native driver

Animation API được thiết kế để liên kết. Bằng cách sử dụng native driver, chúng ta gửi mọi thứ về animation tới native trước khi bắt đâu animation, cho phép native code có thể tác động vào animation trên UI thread mà không cần phải thông qua các cầu nối với một một frame. Một lần Animation được bắt đầu, JS thread có thể bị khóa và không tác động được đến animation.

Sử dụng native driver để chạy nhưng animation thông thường là yêu cầu đơn giản. Chỉ cần thêm useNativeDriver: true tới cấu hình animation khi nó bắt đầu chạy nó.

Animated.timing(this.state.animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // <-- Add this
}).start();

Giá trị Animated chỉ tương ứng với một driver thế nên nếu bạn sử dụng native driver khi start một animation, cần phải chắc chắn rằng mọi animation trên giá trị đố đồng thời sẽ được sử dụng trên native driver.

Native driver đồng thời làm việc với Animated.event. Đây là một sự hữu dụng đặc biệt để animation chạy theo scroll vị trí như là không có native driver. Animation sẽ luôn chạy một frame sau khi cử chỉ được động bộ tới React Native.

Animated.ScrollView // <-- Use the Animated ScrollView wrapper
  scrollEventThrottle={1} // <-- Use 1 here to make sure no events are ever missed
  onScroll={Animated.event(
    [{ nativeEvent: { contentOffset: { y: this.state.animatedValue } } }],
    { useNativeDriver: true } // <-- Add this
  )}
>
  {content}
</Animated.ScrollView>

Bạn có thể xem native driver trong action vừng cách chạy RNTester app sau đố chạy Native Animated Example. Bạn có thể sẽ xem được source code để học cách làm thế nào để các ví dụ chạy.

Cảnh báo

Không phải rằng mọi thứ bạn đều có thể làm với Animated, Nó hiện chỉ hỗ trợ bởi native driver. Giới hạn chính đó là bạn chỉ có thể chạy animate với các thuộc tính không phải dành cho layout: ví dụ như transform và opacity sẽ hoạt động. nhưng flexbox và thuộc tính vị trí thì sẽ không hoạt động. Khi sử dụng Animated.event nó sẽ chỉ làm việc trực tiếp với event mà và không chạy sự kiện bubbling. Điều này có nghĩ là nó sẽ không làm việc với PanResponder nhưng nó làm việc với ScrollView#onScroll.

Bổ sung thêm các ví dụ

RNTester app có nhiều ví dụ cho Animation.

  • AnimatedGratuitousApp
  • NativeAnimationsExample

Nguồn Animations

0