Skip to content

Instantly share code, notes, and snippets.

@IndrekV
Forked from tackkinc/index.android.js
Created December 20, 2017 07:29
Show Gist options
  • Save IndrekV/ce5b52f2a6c9691b04dc22bdb966abcf to your computer and use it in GitHub Desktop.
Save IndrekV/ce5b52f2a6c9691b04dc22bdb966abcf 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,
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment