Skip to content

Instantly share code, notes, and snippets.

@tackkinc
Forked from nidorx/index.android.js
Created July 9, 2016 02:32
Show Gist options
  • Save tackkinc/69f9ad556e925d30343524688b746963 to your computer and use it in GitHub Desktop.
Save tackkinc/69f9ad556e925d30343524688b746963 to your computer and use it in GitHub Desktop.
React Native - Section ListView with search input
/**
* Inspired by "MyASUS - ASUS support" version 2016 https://play.google.com/store/apps/details?id=com.asus.ia.asusapp
* Colors: https://material.google.com/style/color.html#color-color-palette
*
* See online - https://rnplay.org/apps/7qet3A
*/
import React, { Component, } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
View,
ListView,
TouchableHighlight
} from 'react-native';
AppRegistry.registerComponent('App', () => App);
type DataItem = {
title: string;
description: string;
}
const FILTER_TEXT = 'Procurar...';
const EMPTY_TEXT = 'Não existem dados para o filtro informado';
const sections = {
SERVICES: {
color: '#90CAF9',
title: 'Serviço',
data: [
{
title: 'Serviço Rápido',
description: 'FAQ e Tutoriais em vídeo'
},
{
title: 'Locais de Serviço',
description: 'Encontre um centro de serviço perto de você'
},
{
title: 'Rastreador de Reparo',
description: 'Acompanhar de perto os progressos até à data'
},
{
title: 'Entre em contato conosco',
description: 'O seu portal de pesquisa de uso pessoal e exclusivo'
},
{
title: 'Cadastrar meu produto',
description: 'Avalie ou cadastre o produto rapidamente para obter a garantia'
},
{
title: 'Ligue-nos',
description: 'Fale com um assistente para suporte em tempo real'
}
]
},
PRODUCTS: {
color: '#FFA726',
title: 'Produtos',
data:[
{
title: 'Store',
description: 'Torne as compras em movimento mais fáceis'
},
{
title: 'Pesquisar produtos',
description: 'As mais recentes informações sobre o produto ASUS'
},
{
title: 'Notícias ASUS',
description: 'As mais recentes Notícias ASUS'
}
]
},
COMUNITY: {
color: '#9CCC65',
title: 'Comunidade',
data:[
{
title: 'Vídeos mais recentes do produto',
description: 'Assita ao vídeo agora'
},
{
title: 'Facebook',
description: 'Informações, Eventos e ofertas'
},
{
title: 'Twitter',
description: 'Encontre tudo no ASUS'
}
]
},
}
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged: (h1, h2) => h1 !== h2,
});
function filterDatasource(text){
const safe = String(text || '').replace(/([.*^$+?!(){}\[\]\/\\])/g,'\\$1');
const regex = new RegExp(safe, 'i');
const filter = (row) => regex.test(row.title) || regex.test(row.description);
var out = {};
for(var sectionID in sections){
if(!sections.hasOwnProperty(sectionID)){
continue;
}
out[sectionID] = sections[sectionID].data.filter(filter);
}
return ds.cloneWithRowsAndSections(out);
}
class App extends Component {
constructor() {
super();
(this: any).renderRow = this.renderRow.bind(this);
(this: any).renderSeparator = this.renderSeparator.bind(this);
(this: any).renderSectionHeader = this.renderSectionHeader.bind(this);
this.state = {
filter: ''
}
}
render() {
const dataSource = filterDatasource(this.state.filter);
return (
<View style={styles.container}>
<View style={styles.searchContainer}>
<TextInput
style={styles.searchInput}
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
onChangeText={(filter) => this.setState({filter})}
value={this.state.filter}
placeholder={FILTER_TEXT}
testID="explorer_search"
/>
</View>
<ListView
style={styles.list}
dataSource={dataSource}
renderRow={this.renderRow}
renderSectionHeader={this.renderSectionHeader}
renderSeparator={this.renderSeparator}
enableEmptySections={true}
/>
</View>
);
}
renderSectionHeader(sectionData: Array<DataItem>, sectionID: string): ?ReactElement<any> {
const section = sections[sectionID];
const sectionStyle = {
borderBottomColor: section.color
}
const isEmpty = !sectionData || sectionData.length < 1;
let emptyContent;
if(isEmpty){
emptyContent = <Text style={styles.sectionEmpty}>{EMPTY_TEXT}</Text>
}
return (
<View>
<View style={[styles.sectionContainer, sectionStyle]}>
<Text style={[styles.sectionHeader, sectionStyle]}>
{section.title}
</Text>
<View style={[styles.sectionDetail, sectionStyle]} />
</View>
{emptyContent}
</View>
);
}
renderRow(data: DataItem): ?ReactElement<any> {
let handler = () => {
console.log(data);
}
return (
<View>
<TouchableHighlight onPress={handler}>
<View style={styles.row}>
<Text style={styles.rowTitle}>
{data.title}
</Text>
<Text style={styles.rowDescription}>
{data.description}
</Text>
</View>
</TouchableHighlight>
</View>
);
}
renderSeparator(sectionID: string, rowID: any, adjacentRowHighlighted: boolean): ?ReactElement<any> {
return (
<View key={`${sectionID}-${rowID}`} style={styles.separator} />
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop:25,
backgroundColor: '#fff'
},
list: {
backgroundColor: '#eeeeee',
},
sectionContainer: {
backgroundColor: '#fff',
borderBottomWidth: 1,
height: 50,
justifyContent: 'flex-end'
},
sectionHeader:{
paddingLeft: 15,
fontWeight: 'bold',
fontSize: 16,
},
sectionDetail:{
borderBottomWidth: 4,
width: 120
},
sectionEmpty:{
backgroundColor: '#fff',
paddingHorizontal: 15,
paddingVertical: 8,
},
row: {
backgroundColor: 'white',
paddingHorizontal: 15,
paddingTop: 25,
},
rowTitle: {
fontSize: 14,
fontWeight: '500',
},
rowDescription: {
fontSize: 14,
color: '#888888',
lineHeight: 20,
},
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: '#bbbbbb',
marginLeft: 15,
},
searchContainer: {
backgroundColor: '#FFF',
paddingVertical: 10,
borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor: '#bbbbbb',
},
searchInput: {
backgroundColor: 'white',
paddingLeft: 20,
height: 35,
},
});
@jasan-s
Copy link

jasan-s commented Apr 27, 2017

Is it possible to filter using the section headers as well?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment