本地开发react

Let us build a switch component from scratch.

让我们从头开始构建一个开关组件。

Tools used :

使用的工具 :

  • React Native

    React本机
  • React Native Reanimated

    React原生复活
  • Figma

    菲格玛

Design level dissection of Switch Component

开关组件的设计层剖析

Image for post
Fayas fs Fayas fs设计的Switch的通断状态

The components are:

这些组件是:

  1. A rectangle with a border-radius.

    具有边界半径的矩形。
  2. A circle placed absolute inside it.

    在其中绝对放置一个圆。

Let us have a look at the measurements :

让我们来看看测量:

Image for post

The rectangle dimensions are 50 x 28 with a border-radius of ~36.5px.

矩形尺寸为50 x 28,边框半径为〜36.5px。

Image for post

The circle has dimensions of 24 x 24 with a fully rounded border-radius.

该圆的尺寸为24 x 24,边框半径为圆形。

设置React Native项目。 (Setting up React Native Project.)

(Skip to next section, if already done..)

( 如果已经完成,请跳到下一部分。 )

Go ahead to this link https://reactnative.dev/docs/environment-setup#docsNav and follow the steps on creating a new react native project.

转到此链接https://reactnative.dev/docs/environment-setup#docsNav,并按照创建新的react native项目的步骤进行操作。

npx react-native init RNSwitch

To start the application run npx react-native run-ios inside your React Native project folder. Open your project in VS Code and head to the file named App.js.And remove the code under the return statement and replace it with:

要启动应用程序,请在您的React Native项目文件夹中运行npx react-native run-ios 。 在VS Code中打开您的项目并转到名为App.js的文件,然后在return语句下删除该代码并将其替换为:

return {
<>
<View>
</View>
<>
}

You have successfully finished creating a project.

您已成功完成创建项目。

Let us start coding now. 💃

现在让我们开始编码。 💃

The Switch Component will look like this :

开关组件将如下所示:

import PropTypes from "prop-types";
import React, { useEffect, useState } from "react";
import { Pressable, StyleSheet } from "react-native";
import Animated, { interpolateColors, spring } from "react-native-reanimated";


const RNSwitch = ({
  handleOnPress,
  activeTrackColor,
  inActiveTrackColor,
  thumbColor,
  value,
}) => {
  const [switchTranslate] = useState(new Animated.Value(0));
  useEffect(() => {
    if (value) {
      spring(switchTranslate, {
        toValue: 21,
        mass: 1,
        damping: 15,
        stiffness: 120,
        overshootClamping: false,
        restSpeedThreshold: 0.001,
        restDisplacementThreshold: 0.001,
      }).start();
    } else {
      spring(switchTranslate, {
        toValue: 0,
        mass: 1,
        damping: 15,
        stiffness: 120,
        overshootClamping: false,
        restSpeedThreshold: 0.001,
        restDisplacementThreshold: 0.001,
      }).start();
    }
  }, [value, switchTranslate]);
  const interpolateBackgroundColor = {
    backgroundColor: interpolateColors(switchTranslate, {
      inputRange: [0, 22],
      outputColorRange: [inActiveTrackColor, activeTrackColor],
    }),
  };
  const memoizedOnSwitchPressCallback = React.useCallback(() => {
    handleOnPress(!value);
  }, [handleOnPress, value]);


  return (
    <Pressable onPress={memoizedOnSwitchPressCallback}>
      <Animated.View
        style={[styles.containerStyle, interpolateBackgroundColor]}
      >
        <Animated.View
          style={[
            styles.circleStyle,
            { backgroundColor: thumbColor },
            {
              transform: [
                {
                  translateX: switchTranslate,
                },
              ],
            },
            styles.shadowValue,
          ]}
        />
      </Animated.View>
    </Pressable>
  );
};


const styles = StyleSheet.create({
  circleStyle: {
    width: 24,
    height: 24,
    borderRadius: 24,
  },
  containerStyle: {
    width: 50,
    paddingVertical: 2,
    paddingHorizontal: 2,
    borderRadius: 36.5,
  },
  shadowValue: {
    shadowColor: "#000",
    shadowOffset: {
      width: 0,
      height: 2,
    },
    shadowOpacity: 0.23,
    shadowRadius: 2.62,


    elevation: 4,
  },
});


RNSwitch.propTypes = {
  handleOnPress: PropTypes.func.isRequired,
  value: PropTypes.bool.isRequired,
  activeTrackColor: PropTypes.string,
  inActiveTrackColor: PropTypes.string,
  thumbColor: PropTypes.string,
};


RNSwitch.defaultProps = {
  activeTrackColor: "#007AFF",
  inActiveTrackColor: "#F2F5F7",
  thumbColor: "#FFF",
};


export default RNSwitch;

For developers getting confused and going like, “What is exactly happening here?”. Let us break it down.

对于感到困惑和困惑的开发人员,“这里到底发生了什么?”。 让我们分解一下。

Component Structure

组件结构

  1. Pressable

    可按

Pressable is a Core Component wrapper that can detect various stages of press interactions introduced in the latest version of React Native v0.63.0.

Pressable是一个核心组件包装器,可以检测最新版本的React Native v0.63.0中引入的新闻交互的各个阶段。

This wraps our Animated View which has the dimensions of 50 x 28.

这将包装我们的动画视图,该视图的尺寸为50 x 28。

2. Animated View — Rectangle

2. 动画视图—矩形

3. Animated View — Absolute Positioned Circle

3. 动画视图-绝对定位圆

Animations Breakdown

动画细目

  1. Translating the absolute positioned circle on changing the switch state.

    在更改开关状态时平移绝对定位的圆。

It is a super simple smooth Spring Animation.

这是一个超级简单的平滑Spring动画。

spring(switchTranslate, {toValue: 0, // Initial for switchState false and 22 for truemass: 1,damping: 15,stiffness: 120,overshootClamping: false,restSpeedThreshold: 0.001,restDisplacementThreshold: 0.001,}).start();

2. Interpolating the switch track color when the Circle View translates.

2. 插值开关轨道颜色当圆视图平移。

const interpolateBackgroundColor = {backgroundColor: interpolateColors(switchTranslate, {     inputRange: [0, 22],     outputColorRange: [inActiveTrackColor, activeTrackColor],    }),};

This is a cool interpolation function that is imported from the react-native reanimated library.

这是一个很酷的插值函数,是从react-native复活的库中导入的。

The color of the track goes from inActiveTrackColor to activeTrackColor when the switchTranslate value animates to 0 and 22.

当switchTranslate值的动画值分别为0和22时,轨道的颜色将从inActiveTrackColor变为activeTrackColor

So there you go we have our own simple Switch Component where the animations happen in the UI thread.

因此,您可以使用我们自己的简单Switch Component,在其中在UI线程中进行动画处理。

Let us see how it looks in iOS and Android.

让我们看看它在iOS和Android中的外观。

Image for post
Image for post

Woah that looks beautiful 🎉 .

哇好漂亮beautiful。

This is Karthik representing Timeless.

这是 Karthik 代表 Timeless的故事

You can find the repo here and an npm package here.

你可以找到回购这里和NPM包在这里

If you find this blog post helpful, share it with a friend.

如果您发现此博客文章有帮助,请与朋友分享。

If you find any difficulties please feel free to add your comments.

如果发现任何困难,请随时添加您的评论。

翻译自: https://medium.com/timeless/react-native-reanimated-switch-83c331af7877

本地开发react

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐