DEV Community

Cover image for Simple remove transition animation in react native
Sachin Rupani
Sachin Rupani

Posted on

Simple remove transition animation in react native

Hello Devs

Today I would like to share a bit of item remove animation code (translate / scale animation) in react native.

Here's a glimpse of what I've prepared.

Image description

Suppose, you have a list of items in your project (very common example, which most of us deal with in our day to day projects).

export interface ItemEntity {
  id: number;
  taskTitle: string;
}

export const sampleItems: Array<ItemEntity> = [
  {
    id: 1,
    taskTitle: "Breakfast",
  },
  {
    id: 2,
    taskTitle: "Lunch",
  },
  {
    id: 3,
    taskTitle: "Sports",
  },
  {
    id: 4,
    taskTitle: "Dinner",
  },
];
Enter fullscreen mode Exit fullscreen mode

And these items populated into a flat list for displaying inside a react native application

// state data items to be populated in flat list
 const [dataItems, setDataItems] = useState<Array<ItemEntity>>(sampleItems);

// Handler function to remove the item (after animation ends)
  const _handleAfterRemovedAction = (givenEntity: ItemEntity) => {
    setDataItems(
      dataItems.filter(
        (itemIterated: ItemEntity) => itemIterated.id !== givenEntity.id,
      ),
    );
  };

// item in a list
const _renderItem = ({item, index}: {item: ItemEntity; index: number}) => {
    return (
      <ListViewItem
        itemEntity={item}
        onTaskCompletedWithAnimation={_handleAfterRemovedAction}
      />
    );
  };

// Flat List component with some styles
<FlatList
      style={stylesToUse.listViewStyle}
      contentContainerStyle={stylesToUse.listViewContentContainerStyle}
      ListHeaderComponent={_renderHeader()}
      data={dataItems}
      keyExtractor={(item: ItemEntity, index: number) =>
        `${item.id}_${item.taskTitle}_${index}`
      }
      renderItem={_renderItem}
      ItemSeparatorComponent={_renderSeparator}
      showsVerticalScrollIndicator={false}
    />
Enter fullscreen mode Exit fullscreen mode

Now, the animation magic happens in our item component on the click of remove button.

Code Snippet

import {Animated} from 'react-native';

 const _removeItemWithAnimation = () => {
    Animated.parallel([
      Animated.timing(translateAnim, {
        // Negative Value: Translate to left, Positive Value: Translate to right
        toValue: -1000,
        duration: 800,
        useNativeDriver: true,
      }),
    ]).start(() => { /** on end of animation, this block executes, handle your removal logic */});
  };
Enter fullscreen mode Exit fullscreen mode

Full code

ListViewItem.tsx

import {Animated, Text, TouchableOpacity, View} from 'react-native';
import {ItemEntity} from '../../data/ItemEntity';
import {listViewItemStyles} from './styles/ListViewItem.styles';

export type PropsListViewItem = {
  itemEntity: ItemEntity;
  onTaskCompletedWithAnimation?: (givenItem: ItemEntity) => void;
};

export const ListViewItem = ({
  itemEntity,
  onTaskCompletedWithAnimation,
}: PropsListViewItem) => {
  const stylesToUse = listViewItemStyles;

  const translateAnim = new Animated.Value(0); // Initial position

  // trigger remove animation
  const _removeItemWithAnimation = () => {
    Animated.parallel([
      Animated.timing(translateAnim, {
        // Negative Value: Translate to left, Positive Value: Translate to right
        toValue: -1000,
        duration: 800,
        useNativeDriver: true,
      }),
    ]).start(() => onTaskCompletedWithAnimation?.(itemEntity));
  };

  const _renderTitle = () => {
    return (
      <Text style={stylesToUse.titleTextStyle}>{itemEntity.taskTitle}</Text>
    );
  };

  const _renderRemoveAction = () => {
    return (
      <TouchableOpacity
        style={stylesToUse.deleteButtonContainer}
        onPress={() => {
          _removeItemWithAnimation();
        }}>
        <Text style={stylesToUse.deleteButtonTextStyle}>Remove</Text>
      </TouchableOpacity>
    );
  };

  return (
    <Animated.View
      style={[
        stylesToUse.container,
        {
          transform: [{translateX: translateAnim}]
        },
      ]}>
      <View style={stylesToUse.row}>
        {/* Task Title */}
        {_renderTitle()}

        {/* Remove button */}
        {_renderRemoveAction()}
      </View>
    </Animated.View>
  );
};

Enter fullscreen mode Exit fullscreen mode

ListViewItem.styles.ts

import {StyleSheet} from 'react-native';

export const listViewItemStyles = StyleSheet.create({
  container: {
    backgroundColor: '#e1e1e1',
    borderRadius: 8,
    elevation: 1,
  },

  row: {
    padding: 20,
    flexDirection: 'row',
    alignItems: 'center',
    gap: 8,
  },

  titleTextStyle: {
    flex: 1,
    fontSize: 16,
    fontWeight: '500',
    color: '#212121',
  },

  deleteButtonContainer: {
    paddingHorizontal: 12,
    paddingVertical: 8,
    backgroundColor: '#EF5350',
    borderRadius: 24,
  },

  deleteButtonTextStyle: {
    fontSize: 12,
    color: '#ffffff',
  },
});
Enter fullscreen mode Exit fullscreen mode

The translation removal animation can be relevant in following use cases.

  • Marking a task as done/incomplete.
  • Remove an item from the list (we just did)
  • Archiving an item etc.

BONUS

We can also combine the translate animation with scale animation.

const scaleAnim = new Animated.Value(1); // Initial scale value

  const _removeItemWithAnimation = () => {
    Animated.parallel([
      Animated.timing(translateAnim, {
        // Negative Value: Translate to left, Positive Value: Translate to right
        toValue: -1000,
        duration: 800,
        useNativeDriver: true,
      }),
       Animated.timing(scaleAnim, {
        // toValue 0 indicates the item will shrink to size 0
        toValue: 0,
        duration: 800,
        useNativeDriver: true,
      }),
    ]).start(() => onTaskCompletedWithAnimation?.(itemEntity));
  };
Enter fullscreen mode Exit fullscreen mode

And our animated view (in ListViewItem.tsx)

   <Animated.View
      style={[
        stylesToUse.container,
        {
          transform: [{translateX: translateAnim}, {scale: scaleAnim}], 
        },
      ]}> ...
Enter fullscreen mode Exit fullscreen mode

Play around with duration and toValue to experience yourself.

Or you can just use scale animation and omit translate animation based on your requirement.


Quick Bytes:

  • Translation - Translation refers to moving of an item from one direction to the other or we can say position of an item changes entirely.
  • Scale - Item's height/width updates. Either it's enlarged or it shrinks.

Happy coding.

Top comments (0)