1

So, I was getting familiar with reanimated2, for that I'm building a simple todo app, so whenever I check a single todo (a simple toggle state, completed or !completed), I change the text style to line-through so that it appears to be completed, now in order to add some animations, I was trying to combine reanimated to it, but was unsuccessful, so can anyone guide me how to achieve what I want?

const TodoItem = ({ todo }) => {
  const { toggleTodo } = useTodoStore((state) => state);
  const progress = useSharedValue('none');

  useEffect(() => {
    progress.value = withTiming(todo.completed ? 'line-through' : 'none', {
        duration: 1000,
        easing: Easing.linear,
    })
  }, [todo.completed]);

  const textReanimatedStyle = useAnimatedStyle(() => ({
    textDecorationLine: progress.value, // ts error: Type 'string' is not assignable to type 'number | "none" | "underline" | "line-through" | "underline line-through" | undefined'.
  }), []);

  const toggleTodoHandler = () => {
    toggleTodo(todo.id);
  };

  return (
    <Animated.View
      style={styles.container}
      entering={FadeIn}
      exiting={FadeOut}
      layout={Layout.delay(300)}>
      <View style={styles.innerContainer}>
        <TouchableOpacity
          style={styles.checkboxContainer}
          activeOpacity={0.6}
          onPress={toggleTodoHandler}>
          {todo.completed ? (
            <Ionicon name="checkmark" size={20} color={'gray'} />
          ) : null}
        </TouchableOpacity>
        <Animated.Text
          numberOfLines={2}
          style={[
            styles.text,
            textReanimatedStyle,
          ]}>
          {todo.text}
        </Animated.Text>
      </View>
    </Animated.View>
  );
};

Now whenever I toggle complete or not, it throws error saying:

Invalid RCTTextDecorationLineType 'noneNaN'. should be one of: (
  "line-through",
  none,
  underline,
  "underline line-through"
)
dev1ce
  • 1,419
  • 1
  • 19
  • 39

2 Answers2

1

Not sure this is what you wanted to achive. But what I did was can be handle with a state change also without reanimated.

There is an alternate way also. check this answer https://stackoverflow.com/a/65262789/8743951

const textState = useSharedValue('none');
  const [todo, setTodo] = useState<{ text: string; completed: boolean }>({ text: 'complete this', completed: false });

  const textReanimatedStyle = useAnimatedStyle(() => {
    if (textState.value === 'checked') {
      return {
        textDecorationLine: 'line-through',
      };
    }

    return {
      textDecorationLine: 'none',
    };
  }, []);

  const toggleTodoHandler = (): void => {
    textState.value = todo.completed ? 'none' : 'checked';
    setTodo({ ...todo, completed: !todo.completed });
  };

  return (
    <Animated.View style={styles.container} entering={FadeIn} exiting={FadeOut} layout={Layout.delay(300)}>
      <View style={styles.innerContainer}>
        <TouchableOpacity style={styles.checkboxContainer} activeOpacity={0.6} onPress={toggleTodoHandler}>
          {todo.completed ? <Ionicon name="checkmark" size={20} color="gray" /> : null}
        </TouchableOpacity>
        <Animated.Text numberOfLines={2} style={[styles.text, textReanimatedStyle]}>
          {todo.text}
        </Animated.Text>
      </View>
    </Animated.View>
  );
Chari
  • 134
  • 3
0

There is a problem with a concept in general. Animation changes value continuously, so basically it can't change none to line-through as there is no values between. So what animation does? For example you need to change Y position from 0 to 200. You are setting only final Y animated position to 200 and library starts framing for you. So it change position continuously from 0 to 200 based on your frame rate (and other settings, like timing curves) to have a smooth animation. So it will change it in a way (example): 0, 1, 2, 3, 4 ... 200. But it can't change a non-number values continuously.

Jlexyc
  • 507
  • 5
  • 15