> 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 %}

**签名**

```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;
}
```

**参数**

* **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

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

**示例**

```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>
  );
}
```

***

### 检测列表可见性

**SDK 组件：** `IOFlatList`

`IOFlatList`是为了在滚动过程中检测特定元素是否出现在屏幕上或消失而添加了 Intersection Observer 功能的 `FlatList` 组件。使用此组件可以轻松确认并处理列表中的各项是否出现在屏幕上。

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

**签名**

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

**示例**

```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',
  },
});
```

***

### 检测滚动区域可见性 <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%` 是对该位置的可视化示例。

```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>
  );
}
```


---

# 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.
