Native iOS UITableView for React Native with JSON support and more
Native iOS UITableView for React Native with JSON support
Using npm:
npm install react-native-tableview --save
or using yarn:
yarn add react-native-tableview
⚠️ If you are on React Native < 0.60.0, you must use version 2.x.x of this library
If using CocoaPods or React Native version >= 0.60.0
cd ios && pod install && cd ..
For React Native <= 0.59 only
react-native link react-native-tableview
If fails, follow manual linking steps below,
These values are provided to the tableViewStyle
prop.
<TableView tableViewStyle={TableView.Consts.Style.Grouped}>
Style | Value | Preview |
---|---|---|
Plain | TableView.Consts.Style.Plain |
|
Grouped | TableView.Consts.Style.Grouped |
These values are provided to the tableViewCellStyle
prop.
<TableView tableViewCellStyle={TableView.Consts.CellStyle.Default}>
Style | Value | Preview |
---|---|---|
Default | TableView.Consts.CellStyle.Default |
|
Value1 | TableView.Consts.CellStyle.Value1 |
|
Value2 | TableView.Consts.CellStyle.Value2 |
|
Subtitle | TableView.Consts.CellStyle.Subtitle |
These values are provided to the accessoryType
prop on the Item
.
<Item accessoryType={TableView.Consts.AccessoryType.None}>
Style | Value | Preview |
---|---|---|
None | TableView.Consts.AccessoryType.None |
|
Disclosure Indicator | TableView.Consts.AccessoryType.DisclosureIndicator |
|
Disclosure Button | TableView.Consts.AccessoryType.DisclosureButton |
|
Checkmark | TableView.Consts.AccessoryType.Checkmark |
|
Detail Button | TableView.Consts.AccessoryType.DetailButton |
Disclosure Indicator can also be applied by adding the arrow
prop on the
section.
<Section arrow>
Checkmark can also be applied by adding the selected
prop on the Item.
<Item selected>
For a full list of props on all components check out
the typescript definitions file.
scrollTo()
Scrolls to a set of coordinates on the tableview.
/**
* @param x Horizontal pixels to scroll
* @param y Vertical pixels to scroll
* @param animated With animation or not
*/
scrollTo(x: number, y: number, animated: boolean): void;
scrollToIndex()
Scroll to an item in a section
/**
* @param params scroll params
* @param params.index index of the cell
* @param params.section index of the section @default 0
* @param params.animated scroll with animation @default true
*/
scrollToIndex(params: { index: number, section?: number, animated?: boolean }): void;
Items in the list can be either TableView.Item
or TableView.Cell
. An Item
is simply text. A Cell
can be any complex component. However, only Item
s can
be edited or moved. There are also issues with Cell
s re-rendering on data
changes (#19) that can be avoided by using Item
s. If you want to be able to
re-render, edit or move a complex component, use reactModuleForCell
, described
in Editable Complex Components.
() => {
const [loading, setLoading] = useState(true);
const [users, setUsers] = useState([]);
useEffect(() => {
const getUsers = async () => {
const response = await fetch('https://randomuser.me/api/?results=5000');
const data = await response.json();
setLoading(false);
setUsers(
data.results.map(a => ({
name: `${a.name.first} ${a.name.last}`,
id: a.registered,
}))
);
};
getUsers();
}, []);
return (
<View style={{ flex: 1 }}>
<Text style={styles.title}>
{loading ? 'Fetching' : 'Fetched'} 5000 users
</Text>
{loading && <ActivityIndicator />}
<TableView
style={{ flex: 1 }}
tableViewCellStyle={TableView.Consts.CellStyle.Subtitle}
>
<Section>
{users.map(a => (
<Item key={a.id}>{a.name}</Item>
))}
</Section>
</TableView>
</View>
);
};
// list spanish provinces and add 'All states' item at the beginning
const country = 'ES';
return (
<View style={{ flex: 1 }}>
<Text style={styles.title}>Showing States in Spain</Text>
<TableView
style={{ flex: 1 }}
json="states"
selectedValue="ES53"
filter={`country=='${country}'`}
tableViewCellStyle={TableView.Consts.CellStyle.Subtitle}
onPress={event => alert(JSON.stringify(event))}
/>
</View>
);
render() {
return (
<View style={{ flex: 1 }}>
<TableView
style={{ flex: 1 }}
editing={navigation.getParam('editing')}
>
<Section canMove canEdit>
<Item canEdit={false}>Item 1</Item>
<Item>Item 2</Item>
<Item>Item 3</Item>
<Item>Item 4</Item>
<Item>Item 5</Item>
<Item>Item 6</Item>
<Item>Item 7</Item>
<Item>Item 8</Item>
</Section>
</TableView>
</View>
)
}
function reducer(state, action) {
switch (action.type) {
case 'getUsers':
return { ...state, loading: false, users: action.payload };
case 'startRefresh':
return { ...state, refreshing: true };
case 'endRefresh':
return {
...state,
refreshing: false,
amount: state.amount + 10,
users: [...state.users, ...action.payload],
};
default:
return state;
}
}
() => {
const [{ loading, amount, refreshing, users }, dispatch] = useReducer(
reducer,
{
loading: true,
users: [],
refreshing: false,
amount: 10,
}
);
useEffect(() => {
const getUsers = async () => {
const data = await fetchUsers();
dispatch({ type: 'getUsers', payload: data });
};
getUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch('https://randomuser.me/api/?results=10');
const data = await response.json();
return data.results.map(a => ({
name: `${a.name.first} ${a.name.last}`,
id: a.login.uuid,
}));
};
const fetchMore = async () => {
dispatch({ type: 'startRefresh' });
const data = await fetchUsers();
dispatch({ type: 'endRefresh', payload: data });
};
return (
<View style={{ flex: 1 }}>
<Text style={styles.title}>
{loading ? 'Fetching' : 'Fetched'} {amount} users
</Text>
{loading && <ActivityIndicator />}
<TableView
style={{ flex: 1 }}
tableViewCellStyle={TableView.Consts.CellStyle.Subtitle}
canRefresh
refreshing={refreshing}
onRefresh={fetchMore}
>
<Section>
{users.map(a => (
<Item key={a.id}>{a.name}</Item>
))}
</Section>
</TableView>
</View>
);
};
}
The following style props are supported:
tableViewCellStyle
tableViewCellEditingStyle
separatorStyle
contentInset
contentOffset
scrollIndicatorInsets
cellLayoutMargins
cellSeparatorInset
Colors:
textColor
tintColor
selectedTextColor
detailTextColor
separatorColor
headerTextColor
headerBackgroundColor
footerTextColor
Base font:
fontSize
fontWeight
fontStyle
fontFamily
“Subtitle” font:
detailFontSize
detailFontWeight
detailFontStyle
detailFontFamily
Header font:
headerFontSize
headerFontWeight
headerFontStyle
headerFontFamily
Footer font:
footerFontSize
footerFontWeight
footerFontStyle
footerFontFamily
An Item
component takes an image
and an optional imageWidth
prop.
An image
prop can be a string pointing to the name of an asset in your “Asset
Catalog”. In this case an imageWidth
prop is recommended.
<Item image="icon-success.png" imageWidth={40} />
Alternatively, you can require
the image from your local app code. In this case
an imageWidth
is unnecessary.
<Item image={require('../images/icon-success.png')} />
Only Item
s can be edited or moved. However you can create a complex component
that is referenced by an Item using reactModuleForCell
. You will need to do
several things to set this up.
<TableView>
<Item>
s in your TableView, passing props intended for yourApp
root view.For example,
//Should be pure... setState on top-level component doesn't seem to work
class TableViewExampleCell extends React.Component {
render() {
var style = { borderColor: '#aaaaaa', borderWidth: 1, borderRadius: 3 };
// Fill the full native table cell height.
style.flex = 1;
// All Item props get passed to this cell inside this.props.data. Use them to control the rendering, for example background color:
if (this.props.data.backgroundColor !== undefined) {
style.backgroundColor = this.props.data.backgroundColor;
}
return (
<View style={style}>
<Text>
section:{this.props.section},row:{this.props.row},label:
{this.props.data.label}
</Text>
<Text> message:{this.props.data.message}</Text>
</View>
);
}
}
For more examples, see examples/TableViewDemo.
<TableView reactModuleForCell="TableViewExampleCell" >
<Section canEdit={true}>
{this.props.items.map(function(item) {
return (
<Item
key={'i' + item.data.date}
label={item.label}
message={item.message}
/>
);
})}
</Section>
Note that the props you pass must be primitive types: they cannot be objects.
Also, note that the props become properties of the data
prop in your
reactModuleForCell
component. That is, you pass label="foo"
and in your
component you pick it up as this.props.data.label
.
Each cell you render becomes a reuseable root view or App
.
var { AppRegistry } = React;
...
AppRegistry.registerComponent('TableViewExample', () => TableViewExample);
When debugging, you will see the message:
Running application "TableViewExample" with appParams: { /* params */ }. __DEV__ === true, development-level warning are ON, performance optimizations are OFF
multiple times. While slightly annoying, this does not seem to affect
performance. You may also see message
Unbalanced calls start/end for tag 5.