Created
July 8, 2016 17:57
-
-
Save nidorx/faf64d70e6d598b21ffe4c5884ef6295 to your computer and use it in GitHub Desktop.
React Native - Section ListView with search input
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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, | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment