响应式ui_在应用程序远程通知ui中响应本机

响应式ui

A quick recipe to creating an interactive remote notification banner UI in a React Native app, with animations and interactivity.

在React Native应用程序中创建具有动画和交互性的交互式远程通知横幅UI的快速方法。

Remote notifications are an essential part of many types of apps and their use-cases. They are the preferred way for systems to communicate time-sensitive information, from marketing to transactional purposes, to their users individually (using device tokens), a specified target group (using topics), or as a whole. To do this, React Native developers often turn to the ever-popular RNFirebase package by Invertase, which provides a wrapper around the native Firebase SDK for Android and iOS, and taking advantage of the Messaging module to listen to incoming remote messages sent from Firebase Cloud Messaging (FCM).

远程通知是许多类型的应用及其用例的重要组成部分。 它们是系统将时间敏感信息(从营销目的到交易目的)单独(使用设备令牌),指定的目标组(使用主题)或整体传达给用户的首选方式。 为此,React Native开发人员通常会使用Invertase广受欢迎的RNFirebase软件包,该软件包提供了适用于Android和iOS的本地Firebase SDK的包装,并利用Messaging模块来侦听从Firebase Cloud发送的传入远程消息。消息传递(FCM)。

为什么? (Why?)

One might wonder, why the need for a custom notification UI? Won’t remote notifications just automatically be displayed in the notification shade? Looking at the docs, apparently, notifications cannot be displayed while the app is in foreground (while the user is actively using the app) — see table below.

有人可能想知道,为什么需要自定义通知UI? 不会仅在通知阴影中自动显示远程通知? 查看文档,显然,当应用程序处于前台(用户正在积极使用该应用程序时)无法显示通知-参见下表。

here 在此处链接

Notifications will only be shown in the notification shade if the application state is in background or quit/terminated. Hence, some form of in-app UI is needed to display the notifications to the user as they are received.

仅当应用程序状态为后台或退出/终止时,通知才会显示在通知阴影中。 因此,需要某种形式的应用内UI来在收到通知时向用户显示通知。

我看起来怎么样? (How do I look?)

响应式ui_在应用程序远程通知ui中响应本机_第1张图片
Looks easy, right? 看起来很简单,对吧?

As it is fully custom-made, the notification UI design and interactivity can be tailored to match the app’s overall look and feel. The following style is how I prefer to make it myself.

由于它是完全定制的,因此可以定制通知UI设计和交互性,以匹配应用程序的整体外观。 以下样式是我更喜欢自己制作的样式。

通知组件 (Notification component)

Creating a new standalone component to handle all in-app notification logic is key, since the UI would need to be able to be displayed in and interact with all parts of the app. It can then be attached to the root component (or somewhere close).

创建新的独立组件来处理所有应用程序内通知逻辑是关键,因为UI必须能够显示在应用程序的所有部分并与之交互。 然后可以将其附加到根组件(或靠近某处)。

import React, {FC} from 'react';
import NotificationCenter from './NotificationCenter';


const App: FC = () => {
  return (
    <>
      ...
      
    
  );
}


export default App;

Mind the TypeScript :)

注意TypeScript :)

基本使用者介面 (Basic UI)

Now, let’s make a basic design to display the notification title and body. Here I use TailwindRN to handle the styling (because why not). I honestly love using TailwindCSS on the web, and I’m grateful I can get a similar experience in React Native. If you haven’t tried it, I strongly suggest that you give it a shot.

现在,让我们进行基本设计以显示通知标题和正文。 在这里,我使用TailwindRN来处理样式(因为为什么不这样)。 老实说,我喜欢在Web上使用TailwindCSS ,也很高兴能在React Native中获得类似的体验。 如果您还没有尝试过,我强烈建议您试一试。

import {Text, TouchableOpacity, View} from 'react-native';
import React, {FC} from 'react';
import tailwind from 'tailwind-rn';


const NotificationCenter: FC = () => {
  return (
    <>
      
         {}}>
          
            
              Notification Title
            
            
              Notification body lorem ipsum dolor sit amet.
            
          
        
      
    
  );
}


...

Now we’re getting somewhere.

现在我们到了某个地方。

In the example, the component basically displays a dark gray touchable banner, with white title and body text, inside an absolute-ly positioned container (in this case, anchored to the bottom of the screen). The banner uses a touchable component for it to be able to handle actions on presses (more on that later).

在此示例中,组件基本上在absolute放置的容器(在这种情况下,固定在屏幕底部)内显示深灰色可触摸的横幅,带有白色标题和正文。 标语使用可触摸的组件,以便能够处理印刷机上的操作(稍后会详细介绍)。

做个好听众 (Be a good listener)

Next, the component would need to listen (subscribe) to incoming remote messages and store it in state. To do that, it needs to create a listener on mount by invoking the onMessage method of the Messaging module. It also needs to make sure that the remote message is indeed a ‘notification’ (has a title and a body). Display the title and body inside the Text components made previously.

接下来,该组件将需要侦听(订阅)传入的远程消息并将其存储在状态中。 为此,它需要通过调用Messaging模块的onMessage方法在安装时创建侦听器。 它还需要确保远程消息确实是一个“通知”(具有标题和正文)。 在先前制作的“ Text组件中显示标题和正文。

import messaging, {
  FirebaseMessagingTypes,
} from '@react-native-firebase/messaging';
...
import React, {FC, useState, useEffect} from 'react';
...


const NotificationCenter: FC = () => {
  const [
    message,
    setMessage,
  ] = useState(null);
    
  useEffect(() => {
    const unsubscribe = messaging().onMessage((remoteMessage) => {
      if (remoteMessage.notification) {
        setMessage(remoteMessage);
        const timeoutHandler = setTimeout(() => {
          setMessage(null);
        }, 5000);
        return () => {
          setMessage(null);
          clearTimeout(timeoutHandler);
        };
      }
    });
    return () => {
      unsubscribe();
    };
  }, []);
  
  if (!message || !message.notification) {
    return null;
  }
    
  return (
    ...
            
              {message.notification.title}
            
            
              {message.notification.body}
            
    ...
  );
}


...

Go on, try it out! A message sent to the device should automatically display its content in the banner. It should also disappear by itself after 5 seconds.

继续尝试一下! 发送到设备的消息应自动在横幅中显示其内容。 5秒后它也应自行消失。

显示他们的动作! (Show ‘em your moves!)

Now comes the fun part — Animations! But don’t get too carried away, it’s just a notification banner and, at least for me, movement in the UI should be kept minimal and non-distracting. Adding subtle enter and exit transition animations to the component goes a little something like this.

现在来了有趣的部分-动画! 但是不要太着迷,它只是一个通知横幅,至少对我来说,应该将UI中的移动保持在最小限度且无干扰。 将微妙的输入和退出过渡动画添加到组件会有点像这样。

  1. Define a transition animation value, starting from 0. The value would then range from 300 (hidden) to 0 (shown), to be used as the container’s translateY value. Note: 300 is just a convenience value to skip measuring real banner height.

    定义一个transition动画值,从0开始。 然后,该值的范围从300 (隐藏)到0 (显示),用作容器的translateY值。 注意: 300只是方便的值,可跳过横幅的实际高度测量。

  2. Define the ‘exit’ transition animation, which should change the transition value from 0 to 300.

    定义“退出”过渡动画,该动画应将过渡值从0更改为300

  3. Define the ‘enter’ transition animation, which is like the ‘exit’ animation, but the other way around.

    定义“输入”过渡动画,类似于“退出”动画,但反之亦然。
  4. Fire the ‘enter’ animation when a new remote message comes in.

    收到新的远程消息时,触发“输入”动画。
  5. Fire the ‘exit’ animation 5 seconds the message came in (modify the flow in the previous step slightly).

    触发消息“退出”动画5秒钟(稍微修改上一步中的流程)。
  6. Change the container View component to an Animated.View component, and set its translateY value from the transition animation value.

    将容器的View组件更改为Animated.View组件,然后从transition动画值设置其translateY值。

import {Animated, Easing, Text, TouchableOpacity, View} from 'react-native';
import messaging, {
  FirebaseMessagingTypes,
} from '@react-native-firebase/messaging';
import React, {FC, useEffect, useRef, useState} from 'react';


const NotificationCenter: FC = () => {
  ...
 
  const transition = useRef(new Animated.Value(300)).current;
  const exitAnim = useRef(
    Animated.timing(transition, {
      duration: 500,
      easing: Easing.in(Easing.exp),
      toValue: 300,
      useNativeDriver: true,
    }),
  ).current;
  
  useEffect(() => {
    const unsubscribe = messaging().onMessage((remoteMessage) => {
      if (remoteMessage.notification) {
        transition.setValue(300);
        const enterAnim = Animated.spring(transition, {
          toValue: 0,
          useNativeDriver: true,
        });
  
        setMessage(remoteMessage);
        enterAnim.start();
        const timeoutHandler = setTimeout(() => {
          exitAnim.start(() => {
            setMessage(null);
          });
        }, 5000);
        ...
      }
    }
    ...
  }, [transition, exitAnim]);
  
  return (
    <>
      
        ...
      
    
  );
}
  
...

Sick moves! Looks pretty, huh? More importantly, it limits itself to only adding a sense of interactivity and natural movement, by not being too distracting or flashy.

生病的举动! 看起来不错吧? 更重要的是,它不会因过于分散注意力或浮华而使自己仅限于增加互动感和自然运动感。

放开 (Out of the way!)

Another basic feature of notifications we often see is its ability to be dismissed. On the Android notification shade, this is usually done by swiping left or right. Let’s see what we can do with React Native on this front.

我们经常看到的通知的另一个基本特征是其被驳回的能力。 在Android通知栏上,通常是通过向左或向右滑动来完成的。 让我们看看在这方面如何使用React Native。

React Native provides an easy way to handle gestures on a component using its PanResponder API. To handle swipes, the component’s pan handlers would need to respond to horizontal movement and translate it into the container’s translateX value. That movement value can also be interpolated to an opacity value to give it a ‘fading’ effect as it is being dismissed. In sequence, it goes something like this.

React Native提供了一种使用其PanResponder API处理组件上手势的简便方法。 要处理滑动,组件的平移处理程序将需要响应水平移动并将其转换为容器的translateX值。 该运动值也可以插值到不透明度值,以使其在被消除时具有“褪色”效果。 按顺序,它是这样的。

  1. Define a swipe animation value. This value would map to the pan responder’s horizontal movement.

    定义swipe动画值。 该值将映射到声像响应器的水平运动。

  2. Define a resetSwipe animation, to reset the container to its original position if the horizontal movement is not fast enough to qualify as a dismiss action.

    定义一个resetSwipe动画,如果水平移动的速度不够快而无法resetSwipe ,则将容器重置到其原始位置。

  3. Define left and right swipeOut animations, to completely move the container out of the screen if the horizontal movement qualifies as a dismiss action.

    定义左右swipeOut动画,以将容器完全移出屏幕(如果水平移动符合swipeOut动作的资格)。

  4. Define a panResponder to attach to the touchable component and handle gestures acted upon it. Map the onPanResponderMove event’s dx (horizontal movement) to the swipe animation value.

    定义panResponder以附加到可触摸组件并处理在其上执行的手势。 将onPanResponderMove事件的dx (水平移动)映射到swipe动画值。

  5. Attach the panResponder's panHandlers to the touchable component.

    panResponderpanHandlers到可触摸组件。

  6. Add a translateX value to the container component to react to the swipe animation value.

    translateX值添加到容器组件以对swipe动画值做出React。

  7. Define an opacity value as an interpolation from the swipe animation value.

    opacity值定义为swipe动画值的插值。

  8. Add the opacity value to the container component.

    opacity值添加到容器组件。

import {Animated, Dimensions, Easing, PanResponder, Text, View} from 'react-native';
import React, {FC, useState, useEffect, useRef} from 'react';
import tailwind from 'tailwind-rn';


const NotificationCenter: FC = () => {
  ...
  
  const swipe = useRef(new Animated.Value(0)).current;


  const resetSwipe = useRef(
    Animated.timing(swipe, {
      duration: 200,
      toValue: 0,
      easing: Easing.out(Easing.exp),
      useNativeDriver: true,
    }),
  ).current;
  const swipeOutLeft = useRef(
    Animated.timing(swipe, {
      duration: 50,
      toValue: Dimensions.get('screen').width * -1,
      useNativeDriver: true,
    }),
  ).current;
  const swipeOutRight = useRef(
    Animated.timing(swipe, {
      duration: 50,
      toValue: Dimensions.get('screen').width,
      useNativeDriver: true,
    }),
  ).current;
  const opacity = swipe.interpolate({
    inputRange: [
      Dimensions.get('screen').width * -1,
      0,
      Dimensions.get('screen').width,
    ],
    outputRange: [0, 1, 0],
  });


  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => false,
      onMoveShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event([null, {dx: swipe}], {
        useNativeDriver: false,
      }),
      onPanResponderRelease: (e, gs) => {
        if (gs.vx > 0.5) {
          swipeOutRight.start(() => {
            setMessage(null);
          });
        } else if (gs.vx < 0.5) {
          swipeOutLeft.start(() => {
            setMessage(null);
          });
        } else {
          resetSwipe.start();
        }
      },
    }),
  ).current;
  
  useEffect(() => {
    const unsubscribe = messaging().onMessage((remoteMessage) => {
      if (remoteMessage.notification) {
        ...
        swipe.setValue(0);
        ...
      }
    }
    ...
  }


  return (
    <>
      
         {
            exitAnim.start();
          }}>
          
            
              {message.notification.title}
            
            
              {message.notification.body}
            
          
        
      
    
  );
};


...

Now, by swiping left or right fast enough, we can set the notification aside and out of the way. Neat!

现在,通过以足够快的速度向左或向右滑动,我们可以将通知搁置一旁,并且不打扰。 整齐!

And just like that, the app now has the ability to display (with animation) and dismiss in-app remote notifications. What a time to be alive.

就像这样,该应用程序现在可以显示(带有动画)和关闭应用程序内远程通知。 多么活着的时间。

Another great thing about remote messages is that they can contain data (other than title and body), that we can get and use in the app. A couple of common use-cases are:

远程消息的另一个优点是它们可以包含数据(标题和正文除外),我们可以在应用程序中获取和使用这些数据。 几个常见的用例是:

  1. Setting a route/deeplink URL for the app to navigate to when the user presses the notification. This can be achieved in conjunction with React Navigation — stay tuned for an article on this!

    设置应用程序的路由/深层链接URL,以在用户按下通知时导航到该URL。 这可以与React Navigation结合实现-请继续关注此文章!

  2. Setting a specified key to refresh/revalidate data from server. This can be done in conjunction with SWR — also, stay tuned for this!

    设置指定的密钥以刷新/重新验证服务器中的数据。 这可以与SWR一起完成-敬请期待!

Also check out how to make another commonly used mobile app UI, the bottom swipeable modal, in React Native.

还请查看如何在React Native中制作另一个常用的移动应用UI,即底部可滑动模式 。

It’s amazing how React Native with Firebase can enable more and more developers to easily create and ship quality apps in such a short time. I hope this recipe of an article can do a bit of good to everyone taking the time to read. As always, thank you for reading, it means the world to me. Please do leave responses if you like. I would always love to connect to new people, whoever you are. Find me at endyhardy.co for more info.

具有Firebase的React Native如何使越来越多的开发人员能够在如此短的时间内轻松创建和交付高质量的应用程序,真是令人惊讶。 我希望这篇文章的食谱对每个花时间阅读的人都有好处。 与往常一样,感谢您的阅读,对我而言,这意味着世界。 如果您愿意,请留下答复。 无论您是谁,我总是很想结识新朋友。 在endyhardy.co上找到我以获取更多信息。

Have a great day, stay safe, wear your mask, wash your hands, and keep on creating!

祝您有美好的一天,保持安全,戴好口罩,洗手,继续创新!

翻译自: https://levelup.gitconnected.com/react-native-in-app-remote-notification-ui-8e367fcbe96b

响应式ui

你可能感兴趣的:(java,python,leetcode,vue,http,ViewUI)