react_native 项目实战 (4) 自定义分类 使用 CheckBox 以及 数据存储asyncStorage

来源:互联网 发布:仁化县网络问政平台 编辑:程序博客网 时间:2024/06/06 02:04

使用CheckBox

先看下效果图

mark

引入CheckBox 第三方复选框react-native-check-box

npm install react-native-check-box –save //两个横杠

leftText 的Text 大写.又被坑了一次

Checkbox
http://www.searu.org/39207.html

遇到的问题

1, 点击后就隐藏了 解决: 更新react-native-check-box 到最新的 就好了 吐血这个问题

我开始想自己写的 但想着自己写肯定费时费力 不甘心 各种找资料 还是找到了

 "react-native-check-box": "^2.0.2",

npm install react-native-check-box –save 用这个命令 别用github上面的那个readmi说的命令

真的坑啊

2, checkbox 没有勾选 解决: 原因isChecked Checked 我的c是小写 ..

其他的难点就是关于算法的问题了 主要是这几个Checkbox如何布局 大致说下把:

  • 定义一个views数组 里面装了所有的Checkbox
  • 每一行我包裹起来 包裹了两个checkbox 然后用views数组给push进去
  • 需要留出最后一样 通过判断奇数偶数 再把最后一行添加进去

具体看代码把

AsyncStorage使用 进行数据存取

引用

import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    TouchableOpacity,    AsyncStorage} from 'react-native';

通过 setItem方法保存数据 key- value 形式

 AsyncStorage.setItem('custom_key', JSON.stringify(this.state.data))            .then(() => this.refs.toast.show("保存成功"));

获取 getItem 方法获取数据

 AsyncStorage.getItem('custom_key')            .then(value => {                //有用户数据,选中该选中CheckBox                if (value !== null) {                    // console.log(JSON.parse(value));                    this.setState({data: JSON.parse(value)});                } else {                    this.setState({                        data: [{name: 'Android', checked: true},                            {name: 'IOS', checked: true},                            {name: 'React Native', checked: true},                            {name: 'Java', checked: true},                            {name: 'JS', checked: true}]                    });                }            });

下面上完成的代码

/** * Created by liuml on 2017/9/17. */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    AsyncStorage,    TouchableOpacity} from 'react-native';/** * 自定义分类页面 */import NavigationBar from '../compont/NavigationBar';import CheckBox from 'react-native-check-box';import Toast from "react-native-easy-toast"export default class CustomKeyPage extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            data: [{name: 'android', checked: true},                {name: 'IOS', checked: false}]        };    }    handleBack = () => {        this.props.navigation.goBack();    }    getLeftBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                activeOpacity={0.7}                onPress={this.handleBack}>                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}                       style={{width: 24, height: 24}}/>            </TouchableOpacity>        </View>;    }    getRightBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                onPress={this.handleSave}                activeOpacity={0.7}>                <View style={{marginRight: 10}}>                    <Text style={{fontSize: 16, color: '#FFF'}}>保存</Text>                </View>            </TouchableOpacity>        </View>;    }    //保存    handleSave = () => {        //http://lib.csdn.net/article/reactnative/43540   JSON.stringify 字符串转JSON        //AsyncStorage是一个简单的、异步的、持久化的Key-Value存储系统        AsyncStorage.setItem('custom_key', JSON.stringify(this.state.data))            .then(() => this.refs.toast.show("保存成功"));        // console.log(JSON.stringify(this.state.data));    }    //CheckBox 点击  有个疑问为什么在这里设置值就可以不用setState就改变itemchecked,因为是这样调用的()=>this.handlerCBClick(item)    handleClick = (item) => {        // console.log("之前 " + item.checked);        item.checked = !item.checked;        // console.log("之后 " + item.checked);    }    //渲染CheckBox  这里item就是一个对象    renderCheckBox = (item) => {        // console.log(item);        // console.log(item.name + ',' + item.checked);        var leftText = item.name;        return <CheckBox            style={{flex: 1, padding: 10}}            onClick={() => this.handleClick(item)}            leftText={item.name}            isChecked={item.checked}            unCheckedImage={<Image source={require('../../res/images/ic_check_box_outline_blank.png')}                                   style={styles.checkbox}/>}            checkedImage={<Image source={require('../../res/images/ic_check_box.png')} style={styles.checkbox}/>}        />    }    renderViews = () => {        let len = this.state.data.length;        var views = [];  //要绘制的所有多选框,装入views数组        for (let i = 0, j = len - 2; i < j; i += 2) {            views.push((                <View key={`view_${i}`} style={{flexDirection: 'row'}}>                    {this.renderCheckBox(this.state.data[i])}                    {this.renderCheckBox(this.state.data[i + 1])}                </View>            ));        }        //偶数个,剩下最后两个多选框        //奇数个,剩下最后一个多选框        views.push(            <View key={`view_${len - 1}`} style={{flexDirection: 'row'}}>                {len % 2 === 0 ? this.renderCheckBox(this.state.data[len - 2]) :                    <View style={{flex: 1, padding: 10}}></View>}                {this.renderCheckBox(this.state.data[len - 1])}            </View>        );        return views;    }    componentDidMount = () => {        this.loadData();    }    loadData = () => {        //加载本地数据        AsyncStorage.getItem('custom_key')            .then(value => {                //有用户数据,选中该选中CheckBox                if (value !== null) {                    // console.log(JSON.parse(value));                    this.setState({data: JSON.parse(value)});                } else {                    this.setState({                        data: [{name: 'Android', checked: true},                            {name: 'IOS', checked: true},                            {name: 'React Native', checked: true},                            {name: 'Java', checked: true},                            {name: 'JS', checked: true}]                    });                }            });        // console.log(this.state.data);    }    render() {        return <View style={styles.container}>            <NavigationBar                title="自定义分类"                rightButton={this.getRightBtn()}                leftButton={this.getLeftBtn()}/>            <View style={{flexDirection: 'column'}}>                {this.renderViews()}            </View>            <Toast ref="toast"/>        </View>    }}const styles = StyleSheet.create({    container: {        flex: 1    },    checkbox: {        tintColor: '#63B8FF'    }});

看看最终效果图
mark

其实这个第三方CheckBox 有个bug

当属性变化时 并没有刷新状态 那么 需要我进入源码 让他属性变化时 刷新他的状态

主要代码 进入源码后 加入下面的代码

    //当组件接收到新的属性值时被调用    componentWillReceiveProps(nextProps) {        //让状态跟着属性变化        this.setState({isChecked:nextProps.isChecked});    }

下面做一些完善 比对修改前后数据 弹出是否保存对话框

首页最热页面 读取保存的数据

首页的最热页面根据保存的分类读取数据

/** * Created by liuml on 2017/9/11. */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    ListView,    RefreshControl,    TouchableOpacity,    AsyncStorage}from 'react-native';import NavigationBar from "../compont/NavigationBar.js"import ScrollableTabView from "react-native-scrollable-tab-view"import ProjectRow from "../compont/ProjectRow"/** * 最热页面 */export default class PapularPage extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            languages: [                {name: 'Android'},                {name: 'IOS'},                {name: 'React'},                {name: 'Java'},                {name: 'JS'}            ]        };    }    getRightBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity activeOpacity={0.7}>                <Image source={require('../../res/images/ic_search_white_48pt.png')}                       style={{width: 24, height: 24}}></Image>            </TouchableOpacity>            <TouchableOpacity activeOpacity={0.7}>                <Image source={require('../../res/images/ic_more_vert_white_48pt.png')}                       style={{width: 24, height: 24}}></Image>            </TouchableOpacity>        </View>    }    loadLanguages = () => {        // AsyncStorage.clear();        AsyncStorage.getItem('custom_key')            .then((value) => {                console.log("读取的: " + value);                console.log("读取的: " + JSON.parse(value));                if (value != null) {                    this.setState({languages: JSON.parse(value)});                }            });    }    componentDidMount() {        this.loadLanguages();    }    render() {        return <View style={styles.container}>            <NavigationBar                rightButton={this.getRightBtn()}                title="热门"/>            <ScrollableTabView                tabBarBackgroundColor="#63B8FF"                tabBarActiveTextColor="#FFF"                tabBarInactiveTextColor="#F5FFFA"                tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>                {                    this.state.languages.map((item, i) => {                        console.log(item);                        return (item.checked == undefined || item.checked ?                            <PopularTab key={`tab${i}`} tabLabel={item.name}/> : null)                    })                }            </ScrollableTabView>        </View>    }}class PopularTab extends Component {    //这里是Tab 的名字    static defaultProps = {        tabLabel: 'android',    }    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),//是一个优化,节省无用的UI渲染 判断前后数据是否改变 如果改变就更新            isLoading: true        };    }    /*componentDidMount() {     /!*this.setState({     dataSource: this.state.dataSource.cloneWithRows(['first', 'second', 'three'])     }     )*!/     this.loadData();     };*/    //和上面一样的效果  页面加载完成后加载数据    componentDidMount = () => {        this.loadData();    }    //渲染ListView的每一行    renderRow = (obj) => {        return <ProjectRow item={obj}></ProjectRow>        // return <Text>{obj.full_name}</Text>    }    //加载数据    loadData = () => {        this.setState({isLoading: true});        fetch(`https://api.github.com/search/repositories?q=${this.props.tabLabel}&sort=stars`)            .then(response => response.json()) //服务器响应response对象,继续变成json对象            .then(json => {                //更新dataSource                this.setState({                    dataSource: this.state.dataSource.cloneWithRows(json.items),                    isLoading: false,                });            })            .catch((error) => {                console.error(error);            }).done();    }    handleRefresh = () => {        this.loadData();    }    render() {        return <View style={styles.container}>            <ListView                dataSource={this.state.dataSource}                renderRow={this.renderRow}                refreshControl={                    <RefreshControl                        refreshing={this.state.isLoading}                        tintColor="#63B8FF"                        title="正在加载..."                        titleColor="#63B8FF"                        colors={['#63B8FF']}                    />                }            ></ListView>        </View>    }}const styles = StyleSheet.create({    container: {        flex: 1    }});

主要的两段代码

读取本地保存的数据

componentDidMount() {        this.loadLanguages();    }  loadLanguages = () => {        // AsyncStorage.clear();        AsyncStorage.getItem('custom_key')            .then((value) => {                console.log("读取的: " + value);                console.log("读取的: " + JSON.parse(value));                if (value != null) {                    this.setState({languages: JSON.parse(value)});                }            });    }

根据本地数据显示

<ScrollableTabView                tabBarBackgroundColor="#63B8FF"                tabBarActiveTextColor="#FFF"                tabBarInactiveTextColor="#F5FFFA"                tabBarUnderlineStyle={{backgroundColor: "#E7E7E7", height: 2}}>                {                    this.state.languages.map((item, i) => {                        console.log(item);                        return (item.checked == undefined || item.checked ?                            <PopularTab key={`tab${i}`} tabLabel={item.name}/> : null)                    })                }            </ScrollableTabView>

效果图

mark

得注意下我这里做的是重新加载才更新了顶部标题,后面会做下不重新加载,就更新首页的最热标签栏.

下面做下分类排序页面

分类排序

效果图

mark

分类排序 用到了第三方组件

安装命令

npm install react-native-sortable-listview –save

分类页面代码

/** * Created by liuml on 2017/10/22. */import React, {Component} from 'react';import {    AppRegistry,    StyleSheet,    Text,    View,    Image,    TouchableOpacity,    TouchableHighlight,    AsyncStorage,} from 'react-native';import NavigationBar from "../compoent/NavigationBar";import SortableListView from "react-native-sortable-listview";export default class SortKeyPage extends Component {    // 构造    constructor(props) {        super(props);        // 初始状态        this.state = {            data: [],        };    }    doBack = () => {        this.props.navigation.goBack();    }    getLeftBtn = () => {        return <View style={{flexDirection: 'row', alignItems: 'center'}}>            <TouchableOpacity                activeOpacity={0.7}                onPress={this.doBack}>                <Image source={require('../../res/images/ic_arrow_back_white_36pt.png')}                       style={{width: 24, height: 24}}/>            </TouchableOpacity>        </View>;    }    componentDidMount() {        AsyncStorage.getItem("custom_key")            .then(value => {                if (value != null) {                    //只获取checked为true语言,进行排序  forEach 不会返回一个数组 而map会返回一个数组                    let d = [];                    JSON.parse(value).forEach((item) => {                        if (item.checked) {                            d.push(item);                        }                    })                    this.setState({data: d});                    var myorder = Object.keys(this.state.data); //Array of keys                }            })    }    render() {        return <View style={styles.container}>            <NavigationBar                title="语言分类排序"                leftButton={this.getLeftBtn()}/>            <SortableListView                data={this.state.data}                order={Object.keys(this.state.data)}                rowActivationTime="10"                renderRow={row => <RowComponent data={row}/>}                onRowMoved={e => {                    this.state.data.splice(e.to, 0, this.state.data.splice(e.from, 1)[0]);                    this.forceUpdate();                }}            />        </View>    }}//https://github.com/deanmcpherson/react-native-sortable-listview/blob/master/Sortable/example.js 这里是SortableListView github地址 示例代码class RowComponent extends Component {    static defaultProps = {        data: {name: ""}    };    render() {        return <TouchableHighlight            underlayColor="#EEE"            style={styles.item}            {...this.props.sortHandlers}>            <View style={{flexDirection: 'row', paddingLeft: 10}}>                <Image source={require('../../res/images/ic_sort.png')} style={styles.image}/>                <Text>{this.props.data.name}</Text>            </View>        </TouchableHighlight>    }}const styles = StyleSheet.create({    container: {        flex: 1    },    item: {        backgroundColor: '#F8F8F8',        borderBottomWidth: 1,        borderColor: '#EEE',        height: 50,        justifyContent: 'center'    },    image: {        width: 16,        height: 16,        marginRight: 10,        tintColor: '#63B8FF'    }});

项目地址

https://github.com/liudao01/ReactNativeProject

阅读全文
0 0
原创粉丝点击