You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中SearchBar生成的FlatList项高亮实现方案问询

实现FlatList单项高亮选中功能

问题背景

已实现React Native SearchBar,输入时会动态填充FlatList视图,需求是点击FlatList项时仅高亮当前选中项,通过切换item和itemSelected样式实现,且保证同一时间只有一项高亮。

实现方案

核心思路是利用已有的selectedValue状态记录当前选中项的ID,在渲染FlatList每一项时,对比当前项的value与selectedValue,动态应用对应的样式:

  • 修改renderItem函数,根据当前项的value是否等于selectedValue切换样式
  • 点击项时通过handleChangeCancer更新selectedValue,触发FlatList重新渲染,自动取消之前项的高亮

修改后的代码

组件代码

import React, { useState, useEffect } from "react";
import { SearchBar } from 'react-native-elements';
import { StyleSheet, Text, View, ScrollView, ActivityIndicator, FlatList, TouchableOpacity, StatusBar } from "react-native";
import { useNavigation } from '@react-navigation/native';
import constants from './Constants.js';
import { styles } from './CommonStylesWeb.js';
import {SafeAreaView, SafeAreaProvider} from 'react-native-safe-area-context';

const CancerHomepageWeb = ({navigation}) => {
    const [cancerWiki, setCancerWiki] = useState("");
    const [cancerType, setCancerType] = useState("");
    const [selectedValue, setSelectedValue] = useState(null);
    const [selectedLabel, setSelectedLabel] = useState(null);
    const [options, setOptions] = useState([]);
    const [cancerWikiContent, setCancerWikiContent] = useState("");
    const [loadingWiki, setLoadingWiki] = useState(null);
    const [loadingCancers, setLoadingCancers] = useState(null);

    useEffect(() => {
        const getData = async () => {
            setLoadingWiki(true);
            var urlCancerWiki = await constants.getServerURL() + 'cancers_wiki';
            let resultCancerWiki = await fetch(urlCancerWiki, {
                method: "GET", mode: 'cors'
                }).then(response => response.json())
                    .then(response => {
                        if (response.status == 200) {
                            setLoadingWiki(false)
                            setCancerWiki(response.content)
                        } else {
                             setLoadingWiki(false)
                             console.warn(response.message)
                             setCancerWiki(response.message)
                         }
                });
        };
        getData();
    }, []);

    async function handleChangeCancer(value, label) {
      setSelectedValue(value);
      if(label) {
          setCancerWiki("");
          setCancerWikiContent("");
          setLoadingWiki(true);

          const url = await constants.getServerURL() + 'cancer_wiki';
          let result = fetch(url, {
             method: 'POST',
             headers: { 'Content-Type': 'application/json' },
             body: JSON.stringify({ id: value}),
             mode: 'cors'
           }).then(response => response.json())
             .then(response => {
                if (response.status == 200) {
                    setLoadingWiki(false);
                    setCancerWikiContent(response.content)
                    setCancerWiki("")
                } else {
                      setLoadingWiki(false)
                      console.warn(response.message)
                      setCancerWiki(response.message)
                }
           });
      }
    };

    const searchCancers = async() => {
        const url = await constants.getServerURL() + 'cancer_name';
        if (cancerType.length >= 3) {
            setLoadingCancers(true);
            let result = fetch(url, {
               method: 'POST',
               headers: { 'Content-Type': 'application/json' },
               body: JSON.stringify({ cancer_type: cancerType}),
               mode: 'cors'
             }).then(response => response.json())
               .then(response => {
               setOptions([]);
               const optionsTemp = [];
               if (response.status == 200) {
                    setLoadingCancers(false);
                    response.content.map( (cancer) => {
                        optionsTemp.push({label:cancer.name , value: cancer.id});
                    });
                    setOptions(optionsTemp);
               } else {
                   setLoadingCancers(false);
                   console.warn("Error retrieving Cancer");
               }
              });
        }
    }

    // 核心修改:动态切换选中/未选中样式
    const renderItem = ({ item }) => (
            <TouchableOpacity onPress={() => handleChangeCancer(item.value,item.label)}>
              <Text style={item.value === selectedValue ? styles.itemSelected : styles.item}>
                {item.label}
              </Text>
            </TouchableOpacity>
          );

    return (
    <View style={styles.container}>
        <StatusBar style="auto" />
        <View>
            <SearchBar
                    style={styles.searchBar}
                    placeholder="Search by Cancer Type"
                    onChangeText={(cancerType) => setCancerType(cancerType)}
                    value={cancerType}
                    onKeyPress={searchCancers}
                  />
            {loadingCancers &&
                <ActivityIndicator size="large" />
            }
            <FlatList
                  data={options}
                  renderItem={renderItem}
                  keyExtractor={item => item.value}
                  style={styles.dropdown}
                />
        </View>
        <View>
            <Text style={{ fontSize: 20 }}>Cancers</Text>
        </View>
        <ScrollView>
             <View style={styles.wikiView}>
                 <Text>{cancerWikiContent}</Text>
                 <Text>{cancerWiki}</Text>
                 {loadingWiki &&
                     <SafeAreaProvider>
                         <SafeAreaView style={[styles.loadingContainer, styles.loadingHorizontal]}>
                           <ActivityIndicator size="large" />
                         </SafeAreaView>
                       </SafeAreaProvider>
                 }
             </View>
        </ScrollView>
    </View>
);
}

export { CancerHomepageWeb };

样式代码(保持原样式即可)

import { StyleSheet } from "react-native";
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';

const styles = StyleSheet.create({
  searchBar: {
      width: wp(60),
      height: 10,
      paddingLeft: 10,
      flex: 1,
      alignItems: "center",
      justifyContent: "center",
    },
   dropdown: {
        maxHeight: 150,
        backgroundColor: 'white',
        borderWidth: 1,
        borderColor: 'gray',
        borderRadius: 5,
        marginTop: 5,
      },
      item: {
        padding: 15,
        fontSize: 16,
      },
      itemSelected: {
        padding: 15,
        fontSize: 16,
        backgroundColor: '#2196F3',
        color: "white"
      }
});

export { styles };

关键说明

  • 利用selectedValue作为唯一选中标识,每次点击项时更新该状态,FlatList会自动重新渲染所有项,仅为匹配项应用高亮样式
  • 搜索新内容时,options被重置,若selectedValue无匹配项,高亮会自动消失,符合交互逻辑

内容的提问来源于stack exchange,提问作者MattJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:48:10