首页 > 解决方案 > 如何在 React Native 中涂抹部分视图?

问题描述

我想在用户拖动手指的任何地方模糊图像的一部分,我不想模糊整个图像。这是我做模糊的hacky方式

@react-native-community/blur用于模糊视图

const MyView = () => {
  const [locations, setLocation] = useState([]);
  const [top, setTop] = useState();
  const [left, setLeft] = useState();

  return (
    <>
      <View
        style={styles.container}
        onTouchEnd={(event) => {
          console.log(event.nativeEvent.locationX);
          console.log(event.nativeEvent.locationY);
          setLocation([
            ...locations,
            {
              right: event.nativeEvent.locationX,
              bottom: event.nativeEvent.locationY,
              top,
              left,
            },
          ]);
        }}
        onTouchStart={(event) => {
          console.log('S' + event.nativeEvent.locationX);
          console.log('S' + event.nativeEvent.locationY);
          setLeft(event.nativeEvent.locationX);
          setTop(event.nativeEvent.locationY);
        }}>
        <ImageBackground
          style={{width, height}}
          source={{
            uri:
              'https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80',
          }}>
          <Text>Hi there </Text>
        </ImageBackground>
      </View>
      {locations.map((l, index) => {
        return (
          <BlurView
            key={index.toString()}
            style={{
              width: l.right - l.left,
              height: l.bottom - l.top,
              backgroundColor: 'rgba(0,0,0,0.1)',
              position: 'absolute',
              top: parseFloat(l.top),
              left: parseFloat(l.left),
              right: parseFloat(l.right),
              bottom: parseFloat(l.bottom),
              // blurR,
              // opacity: 0.4,
            }}
            blurType="light"
            blurAmount={4}
            reducedTransparencyFallbackColor="white"
          />
        );
      })}
    </>);
};

这是一种在用户拖动手指的地方涂抹图像的一部分的非常老套的方法。在 Android 上,只要我将手指移动到两个以上的位置,应用程序就会停止响应。有谁知道一种更好的方法来涂抹部分视图而不是模糊用户拖动手指的整个图像视图

标签: androidiosreact-native

解决方案


您可以使用 PanResponder。我为您开发了一个示例应用程序。世博小吃没有模糊视图,但我想你可以轻松地将样本转换为你想要的。这是示例代码:

import React, { useState, useRef } from 'react'
import { StyleSheet, View, ImageBackground, PanResponder, Animated } from 'react-native'

const CIRCLE_RADIUS = 60

const IAmTheBlurComponent = () => {
  return (
    <View style={[StyleSheet.absoluteFill, { backgroundColor: 'pink', opacity: 0.5 }]}></View>
  )
}

const Component = () => {
  const [pointers, setPointers] = useState([])
  const refs: any = useRef({}).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onMoveShouldSetPanResponderCapture: () => true,
      onPanResponderStart: (evt) => {
        setPointers(evt.nativeEvent.touches.map(touch => touch.identifier))
        evt.nativeEvent.touches.forEach((event) => {
          refs[event.identifier] = { x: new Animated.Value(event.pageX), y: new Animated.Value(event.pageY) }
        })
      },
      onPanResponderMove: (evt) => {
        evt.nativeEvent.touches.forEach((event) => {
          refs[event.identifier].x.setValue(event.pageX)
          refs[event.identifier].y.setValue(event.pageY)
        })
      },
      onPanResponderEnd: (evt) => {
        setPointers(evt.nativeEvent.touches.map(touch => touch.identifier))
      },
    })
  ).current

  return (
    <ImageBackground
      style={{
        flex: 1,
        position: 'relative'
      }}
      source={{
        uri:
          'https://images.unsplash.com/photo-1593642634315-48f5414c3ad9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1050&q=80',
      }}
      {...panResponder.panHandlers}
    >
      {pointers.map((pnt) => {
        return (
          <Animated.View
            key={pnt}
            style={{
              overflow: 'hidden',
              height: CIRCLE_RADIUS * 2,
              width: CIRCLE_RADIUS * 2,
              borderRadius: CIRCLE_RADIUS,
              position: 'absolute',
              transform: [
                {
                  translateX: Animated.subtract(refs[pnt].x, CIRCLE_RADIUS)
                },
                {
                  translateY: Animated.subtract(refs[pnt].y, CIRCLE_RADIUS)
                }
              ]
            }}
          >
            <IAmTheBlurComponent />
          </Animated.View>
        )
      })}
    </ImageBackground>
  )
}

export default function App() {
  return (
    <View style={styles.container}>
      <Component />
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
})

对于流畅的动画,您可以选择 Reanimated 库。我没有使用 ValueXY 或类似的东西,因此您可以轻松地将该样本转换为重新激活的样本。

这是样品博览会小吃:https ://snack.expo.io/@kubilaysali/suspicious-ice-cream


推荐阅读