> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/react-native/impression.md).

# 曝光检测

可以检测滚动视图或列表中某个元素是否出现在屏幕上。

### 检测可见性

**SDK 组件：** `InView`

`InView` 该组件用于检测元素何时开始出现在屏幕上或消失。只要元素开始在屏幕上露出一点， `onChanged` 处理函数就会被调用，并且第一个参数会传入 `true` 。相反，当元素从屏幕上消失时， `false` 值会传入。 `onChanged` 处理函数的第二个参数会传入元素的屏幕可见比例。可见比例值在 `0`到 `1.0` 之间。例如， `0.2`被传入时，表示该组件有 20% 显示在屏幕上。

{% hint style="info" %}
**请注意**

`InView`必须 `IOContext`包含的 [IOScrollView](#scroll-impression-area) 或 [IOFlatList](#%EB%A6%AC%EC%8A%A4%ED%8A%B8-%EB%85%B8%EC%B6%9C-%EA%B0%90%EC%A7%80%ED%95%98%EA%B8%B0) 内部使用。如果在 `IOContext` 外部使用， `IOProviderMissingError`会发生错误。
{% endhint %}

**签名**

{% code collapsedlinecount="10" %}

```typescript
class InView<T = ViewProps> extends PureComponent<InViewProps<T>> {
  static contextType: import('react').Context<IOContextValue>;
  static defaultProps: Partial<InViewProps>;
  context: undefined | IOContextValue;
  mounted: boolean;
  protected element: Element;
  protected instance: undefined | ObserverInstance;
  protected view: any;
  constructor(props: InViewProps<T>);
  componentDidMount(): void;
  componentWillUnmount(): void;
  protected handleChange: (inView: boolean, areaThreshold: number) => void;
  protected handleRef: (ref: any) => void;
  protected handleLayout: (event: LayoutChangeEvent) => void;
  measure: (...args: any) => void;
  measureInWindow: (...args: any) => void;
  measureLayout: (...args: any) => void;
  setNativeProps: (...args: any) => void;
  focus: (...args: any) => void;
  blur: (...args: any) => void;
  render(): import('react/jsx-runtime').JSX.Element | null;
}
```

{% endcode %}

**参数**

* **props** · 必需 · `Object`

  传递给组件的 props 对象。

  * **props.children** · 必需 · `React.ReactNode`

    将在组件下方渲染的子组件。
* **prop.asReact.ComponentType** · `View`

  指定要实际渲染的组件。默认值是 [View](https://reactnative.dev/docs/view) 组件。
* **triggerOnceboolean** · `false`

  当元素第一次出现在屏幕上时，只想调用一次 `onChange` 回调时使用此选项。
* onLayout(event: LayoutChangeEvent) => void

  布局发生变化时调用的回调函数。
* onChange(inView: boolean, areaThreshold: number) => void

  当元素出现在屏幕上或消失时调用的回调函数。第一个参数传入可见状态，第二个参数传入可见比例。

**示例**

{% code collapsedlinecount="10" %}

```tsx
import { LayoutChangeEvent, View, Text, Dimensions } from 'react-native';
import { InView, IOScrollView } from '@granite-js/react-native';

function InViewExample() {
  const handleLayout = (event: LayoutChangeEvent) => {
    console.log('布局已更改', event.nativeEvent.layout);
  };

  const handleChange = (inView: boolean, areaThreshold: number) => {
    if (inView) {
      console.log(`${areaThreshold * 100}% 比例显示在屏幕上`);
    } else {
      console.log('未显示在屏幕上');
    }
  };

  return (
    <IOScrollView>
      <View style={{ height: HEIGHT, width: '100%', backgroundColor: 'blue' }}>
        <Text style={{ color: 'white' }}>请向下滚动</Text>
      </View>
      <InView onLayout={handleLayout} onChange={handleChange}>
        <View style={{ width: 100, height: 300, backgroundColor: 'yellow' }}>
          <View
            style={{
              position: 'absolute',
              top: 30,
              width: 100,
              height: 1,
              borderWidth: 1,
            }}
          >
            <Text style={{ position: 'absolute', top: 0 }}>10% 位置</Text>
          </View>
        </View>
      </InView>
    </IOScrollView>
  );
}
```

{% endcode %}

***

### 检测列表可见性

**SDK 组件：** `IOFlatList`

`IOFlatList`是添加了 Intersection Observer 功能，用于检测滚动过程中某个元素是否出现在屏幕上或消失的 `FlatList` 组件。使用该组件可以轻松确认并处理列表中每一项是否出现在屏幕上。

`InView`一起使用时，可以确认各元素的可见状态。作为子元素包含的 `InView` 组件会 `IOFlatList`通过 的观察功能检测元素是否出现在屏幕上，并根据可见状态触发事件。

**签名**

{% code collapsedlinecount="10" %}

```typescript
IOFlatList: typeof IOFlatListFunction;
```

{% endcode %}

**示例**

{% code collapsedlinecount="10" %}

```tsx
import { ReactNode, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { InView, IOFlatList } from '@granite-js/react-native';

const mockData = Array.from({ length: 30 }, (_, i) => ({ key: String(i) }));

function FlatListPage() {
  return <IOFlatList data={mockData} renderItem={({ item }) => <InViewItem>{item.key}</InViewItem>} />;
}

function InViewItem({ children }: { children: ReactNode }) {
  const [visible, setVisible] = useState(false);

  return (
    <InView onChange={setVisible}>
      <View style={styles.item}>
        <Text>{children}</Text>
        <Text>{visible ? 'visible' : ''}</Text>
      </View>
    </InView>
  );
}

const styles = StyleSheet.create({
  item: {
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#ddd',
  },
});
```

{% endcode %}

***

### 检测滚动区域可见性 <a href="#scroll-impression-area" id="scroll-impression-area"></a>

**SDK 组件：** `IOScrollView`, `ImpressionArea`

[`IOScrollView`](#scroll-impression-area)和 [`ImpressionArea`](#scroll-impression-area)结合使用，可以确认滚动视图中元素是否出现在屏幕上。某个元素在屏幕上显示达到一定比例以上时， `onImpressionStart` 回调会被调用。

[`ImpressionArea`](#scroll-impression-area)的 `areaThreshold` 值后，当元素可见比例达到设定比例以上时， `onImpressionStart` 回调会被调用。

{% hint style="info" %}
**`IOScrollView` 只能在内部使用**

[`ImpressionArea`](#scroll-impression-area)必须 [`IOScrollView`](#scroll-impression-area) 内部。

否则， `在 IOContext.Provider 外部使用了。`会发生这样的错误。
{% endhint %}

#### 在滚动视图中处理元素显示达到 20% 以上时

下面的代码是元素高度 `100px`的元素在 [`IOScrollView`](#scroll-impression-area)到 `20%`以上显示时`onImpressionStart`会被调用的示例。

红色线条是 `100px`的 `20%` 位置的可视化标示示例。

{% code collapsedlinecount="10" %}

```tsx{14,18,22-27,37-38}
import { createRoute, ImpressionArea, IOScrollView } from '@granite-js/react-native';
import { ReactNode } from 'react';
import { Alert, Text, View } from 'react-native';

export const Route = createRoute('/image', {
  component: Image,
});

/* 用于滚动的虚拟内容 */
const dummies = new Array(10).fill(undefined);

/** 20% 位置 */
const AREA_THRESHOLD = 0.2; // [!code focus]

function Image() {
  return (
    <IOScrollView> // [!code focus]
      {dummies.map((_, index) => {
        return <DummyContent key={index} text={10 - index} />;
      })}
      <ImpressionArea // [!code focus]
        areaThreshold={AREA_THRESHOLD} // [!code focus]
        onImpressionStart={() => { // [!code focus]
          Alert.alert('Impression Start'); // [!code focus]
        }} // [!code focus]
      > // [!code focus]
        <View
          style={{
            width: '100%',
            height: 100,
            backgroundColor: 'blue',
          }}
        >
          <DebugLine areaThreshold={AREA_THRESHOLD} />
        </View>
      </ImpressionArea> // [!code focus]
    </IOScrollView> // [!code focus]
  );
}

/** 以可视化方式显示比例的调试组件 */
function DebugLine({ areaThreshold }: { areaThreshold: number }) {
  return (
    <View
      style={{
        position: 'absolute',
        top: `${areaThreshold * 100}%`,
        width: '100%',
        height: 1,
        backgroundColor: 'red',
      }}
    />
  );
}

/** 虚拟区域 */
function DummyContent({ text }: { text: ReactNode }) {
  return (
    <View
      style={{
        width: '100%',
        height: 100,
        borderWidth: 1,
      }}
    >
      <Text>{text}</Text>
    </View>
  );
}
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/react-native/impression.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
