irpas技术客

React05_轩轩990218

网络 5354

React05

作业1: 斗鱼

// rnc import React, {Component} from 'react'; import { Dimensions, Image, ImageBackground, ScrollView, Text, TouchableOpacity, View, } from 'react-native'; const {width, height} = Dimensions.get('screen'); function rpx(fs) { return (width / 750) * fs; } export default class App extends Component { state = {data: []}; loadMore() { // 分页的处理方式: 不同服务器不同, 斗鱼的服务器是 传递已有数据的个数 let url = 'http://capi.douyucdn.cn/api/v1/live?limit=20&offset=' + this.state.data.length; fetch(url) .then((res) => res.json()) .then((res) => { this.state.data = this.state.data.concat(res.data); this.setState({}); }); } componentDidMount() { // 生命周期: 挂载时 let url = 'http://capi.douyucdn.cn/api/v1/live?limit=20&offset=0'; fetch(url) .then((res) => res.json()) .then((res) => { console.log(res); this.setState({data: res.data}); }); } show() { return this.state.data.map((item, index) => { // 比例:320x180 let space = 10; let box_w = (750 - space * 3) / 2; // 按比例算图片高 let img_h = (box_w * 180) / 320; // online: 过万的要转 let online = item.online; if (online >= 10000) { online /= 10000; online = online.toFixed(1) + '万'; } return ( <View key={index} style={{ width: rpx(box_w), marginLeft: rpx(space), marginTop: rpx(space), }}> <ImageBackground source={{uri: item.room_src}} style={{width: '100%', height: rpx(img_h)}}> <View style={{ backgroundColor: 'rgba(0,0,0,0.5)', padding: rpx(5), flexDirection: 'row', justifyContent: 'space-between', marginTop: 'auto', }}> <Text style={{color: 'white'}}>{item.nickname}</Text> <Text style={{color: 'white'}}>{online}</Text> </View> </ImageBackground> <Text style={{backgroundColor: 'lightgray', padding: rpx(10)}}> {item.room_name} </Text> </View> ); }); } render() { return ( <ScrollView> <View style={{flexDirection: 'row', flexWrap: 'wrap'}}> {this.show()} <TouchableOpacity onPress={() => this.loadMore()} style={{ margin: rpx(10), alignItems: 'center', paddingVertical: rpx(10), backgroundColor: 'green', width: rpx(750 - 20), borderRadius: rpx(10), }}> <Text style={{color: 'white', fontSize: rpx(32)}}>加载更多</Text> </TouchableOpacity> </View> </ScrollView> ); } }

作业2:

// 布局练习 // rncs import React, {Component} from 'react'; import { Text, StyleSheet, View, ImageBackground, StatusBar, Dimensions, TouchableOpacity, Image, TextInput, } from 'react-native'; // height: 屏幕高 const {width, height} = Dimensions.get('screen'); // 宽度的适配用rpx. 高度和宽度有比例关系的 用rpx function rpx(fs) { return (width / 750) * fs; } export default class App extends Component { render() { return ( <ImageBackground source={require('./assets/bg.jpg')} // 高度不要写100% 会因为弹出键盘 父元素屏幕高度缩小 而变更 // 直接写死高度 为屏幕高 可以防止键盘弹出 style={{width: '100%', height}} blurRadius={8}> {/* 沉浸式 */} <StatusBar backgroundColor="rgba(0,0,0,0)" translucent /> <TouchableOpacity style={ss.left_arrow}> <Image source={require('./assets/left.png')} /> </TouchableOpacity> <Text style={ss.title}>飞车</Text> <View style={ss.content}> <TextInput placeholder="邮箱/手机号" style={ss.input} /> <TextInput placeholder="密码" secureTextEntry style={[ss.input, {marginVertical: 20}]} /> <TouchableOpacity style={ss.login_btn}> <Text style={{fontSize: rpx(40)}}>登录</Text> </TouchableOpacity> <View style={ss.account}> <TouchableOpacity> <Text style={{color: 'white', fontSize: rpx(30)}}>忘记密码?</Text> </TouchableOpacity> <TouchableOpacity> <Text style={{color: 'white', fontSize: rpx(30)}}>手机注册</Text> </TouchableOpacity> </View> </View> <View style={{position: 'absolute', bottom: 20, left: 0, right: 0}}> <Text style={{ color: 'white', textAlign: 'center', marginBottom: 40, fontSize: rpx(25), }}> 第三方账号直接登录 </Text> <View style={{flexDirection: 'row', justifyContent: 'center'}}> <TouchableOpacity style={ss.icon}> <Image source={require('./assets/qq.png')} style={{width: rpx(70), height: rpx(70)}} /> </TouchableOpacity> <TouchableOpacity style={[ss.icon, {marginHorizontal: rpx(40)}]}> <Image source={require('./assets/webo.png')} style={{width: rpx(70), height: rpx(70)}} /> </TouchableOpacity> <TouchableOpacity style={ss.icon}> <Image source={require('./assets/wexin.png')} style={{width: rpx(70), height: rpx(70)}} /> </TouchableOpacity> </View> </View> </ImageBackground> ); } } const ss = StyleSheet.create({ icon: { backgroundColor: 'white', padding: rpx(20), borderRadius: rpx(55), }, account: { marginTop: 30, flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: rpx(20), }, login_btn: { backgroundColor: 'yellow', borderRadius: rpx(10), paddingVertical: rpx(13), alignItems: 'center', }, input: { fontSize: rpx(35), backgroundColor: 'white', borderRadius: rpx(10), paddingHorizontal: rpx(15), color: 'black', }, content: { marginHorizontal: rpx(50), marginTop: 80, // borderWidth: 1, }, title: { fontSize: rpx(80), color: 'white', alignSelf: 'center', marginTop: 50, }, left_arrow: { marginTop: 30, marginLeft: rpx(30), alignSelf: 'flex-start', }, }); FlatList

高性能的列表组件:

完全跨平台。支持水平布局模式。行组件显示或隐藏时可配置回调事件。支持单独的头部组件。支持单独的尾部组件。支持自定义行间分隔线。支持下拉刷新。支持上拉加载。支持跳转到指定行(ScrollToIndex)。支持多列布局。 // FlatList: 高性能的列表组件 // rnc import React, {Component} from 'react'; import {FlatList, Text, View} from 'react-native'; export default class App extends Component { names = ['lucy', 'jjjj', '东东', '亮亮', '然然', '小新', 'shirley', 'kk']; render() { /** * 列表渲染的做法 目前分两种: * 1. 手动: 我们自己写循环遍历操作, 反馈样式 * 2. 自动: FlatList 相当一个小助手 -- 只需要告知相关的信息, 就会自动形成列表 */ // 3个核心属性: // 1. data: 用于设置要循环的数据数组 // 2. renderItem: 用于设置每个数据项对应的UI // 3. keyExtractor: 每条UI 对应的唯一标识 return ( <FlatList data={this.names} renderItem={this._renderItem} // 返回值要求是 string; index是number类型, 必须转字符串 // ()=> {return xxx;} 语法糖: ()=> xxx keyExtractor={(item, index) => index + ''} /> ); } // data是 数组中的每个元素 _renderItem = (data) => { // data: {index:序号, item:值} console.log(data); return ( <View style={{backgroundColor: data.index % 2 == 0 ? 'green' : 'orange'}}> <Text style={{fontSize: 40}}>{data.item}</Text> </View> ); }; } 网易新闻 // 新闻列表 // rnc import React, {Component} from 'react'; import {ActivityIndicator, FlatList, Image, Text, View} from 'react-native'; export default class App extends Component { state = {result: [], refreshing: false}; componentDidMount() { let url = 'https://api.apiopen.top/getWangYiNews?page=1'; fetch(url) .then((res) => res.json()) .then((res) => { console.log(res); this.setState({result: res.result}); }); } render() { /** * 核心属性: * data: 要显示的数据数组 * renderItem: 每条数据的样子 * keyExtractor: 每一条的唯一标识 * * 其它属性: * ItemSeparatorComponent: 元素间的分割组件 * ListHeaderComponent: 表头 * ListFooterComponent: 表尾 * onEndReachedThreshold: 触底阈值. 当剩余未显示区域的高度 占据显示区域高度百分比. 例如0.1 剩余高度 是显示区域高度 10% 大小时, 触发 onEndReached 方法 * onEndReached: 触底时触发 * refreshing: 下拉动画是否显示 * onRefresh: 下拉时触发的方法 */ return ( <FlatList data={this.state.result} renderItem={this._renderItem} keyExtractor={(item, index) => index + ''} ItemSeparatorComponent={() => ( <View style={{height: 2, backgroundColor: 'gray'}} /> )} ListHeaderComponent={this._ListHeaderComponent} ListFooterComponent={this._ListFooterComponent} onEndReached={this._onEndReached} onEndReachedThreshold={0.1} onRefresh={this._onRefresh} refreshing={this.state.refreshing} /> ); } _onRefresh = () => { this.setState({refreshing: true}); let url = 'https://api.apiopen.top/getWangYiNews?page=1'; fetch(url) .then((res) => res.json()) .then((res) => { this.setState({result: res.result, refreshing: false}); this.page = 1; }); }; page = 1; _onEndReached = () => { // alert('侦测到触底操作'); let url = 'https://api.apiopen.top/getWangYiNews?page=' + (this.page + 1); fetch(url) .then((res) => res.json()) .then((res) => { this.state.result = this.state.result.concat(res.result); //合并 this.setState({}); //刷新 this.page++; //页数更新成当前页 }); }; _ListFooterComponent = () => ( <View style={{ alignItems: 'center', paddingVertical: 10, backgroundColor: 'lightgray', }}> <ActivityIndicator color="red" size="large" /> <Text style={{fontSize: 20}}>加载中...</Text> </View> ); _ListHeaderComponent = () => ( <Text style={{ backgroundColor: 'red', color: 'white', textAlign: 'center', fontSize: 40, }}> 网易新闻 </Text> ); // 箭头函数 可以规避 this 问题 // 超级简化: 参数直接解包 _renderItem = ({index, item}) => { if (!item.image) return <View />; //容错, 有不存在的, 就不显示 // console.log(data); //data: {index:序号, item: 数据} // 快速解包 // let {index, item} = data; return ( <View style={{padding: 4, flexDirection: 'row'}}> <Image source={{uri: item.image}} style={{width: 140, height: 88}} /> {/* flex: 份数; 代表宽度为剩余大小 */} <View style={{flex: 1, justifyContent: 'space-evenly', marginLeft: 10}}> <Text style={{fontSize: 20}}>{item.title}</Text> <Text style={{color: 'gray', fontSize: 18}}>{item.passtime}</Text> </View> </View> ); }; } 美图浏览 // 美图浏览器 // rnc import React, {Component} from 'react'; import { ActivityIndicator, Dimensions, FlatList, Image, Modal, Text, TouchableOpacity, View, } from 'react-native'; const {width, height} = Dimensions.get('screen'); function rpx(fs) { return (width / 750) * fs; } export default class App extends Component { // showModal: 控制模态窗口的可见性 state = {result: [], refreshing: false, showModal: false, bigImg: ''}; componentDidMount() { let url = 'https://api.apiopen.top/getImages?page=7'; fetch(url) .then((res) => res.json()) .then((res) => { console.log(res); this.setState({result: res.result}); }); } render() { // numColumns: 列数 return ( <View> {/* 新的组件: Modal 模态窗口 -- 浮在已有内容上 */} {/* visible: 可见 可视 */} <Modal visible={this.state.showModal}> <TouchableOpacity onPress={() => this.setState({showModal: false})} activeOpacity={0.8} style={{backgroundColor: 'green', height: '100%'}}> <Image style={{width: '100%', height: '100%'}} source={{uri: this.state.bigImg}} /> </TouchableOpacity> </Modal> <FlatList data={this.state.result} keyExtractor={(item, index) => index + ''} renderItem={this._renderItem} numColumns={3} ListFooterComponent={this._ListFooterComponent} onEndReachedThreshold={0.1} onEndReached={this._onEndReached} onRefresh={this._onRefresh} refreshing={this.state.refreshing} /> </View> ); } _onRefresh = () => { this.setState({refreshing: true}); let url = 'https://api.apiopen.top/getImages?page=7'; fetch(url) .then((res) => res.json()) .then((res) => { this.setState({result: res.result, refreshing: false}); this.page = 7; }); }; page = 7; _onEndReached = () => { let url = 'https://api.apiopen.top/getImages?page=' + (this.page + 1); fetch(url) .then((res) => res.json()) .then((res) => { this.state.result = this.state.result.concat(res.result); this.setState({}); this.page++; }); }; _ListFooterComponent = () => { return ( <View style={{alignItems: 'center', paddingVertical: rpx(16)}}> <ActivityIndicator color="green" size="large" /> <Text style={{fontSize: rpx(30)}}>加载中...</Text> </View> ); }; _renderItem = ({item, index}) => { let space = 15; let box_w = (750 - 4 * space) / 3; let box_h = box_w * 1.5; return ( <TouchableOpacity onPress={() => this.setState({showModal: true, bigImg: item.img})} activeOpacity={0.8} style={{ marginLeft: rpx(space), width: rpx(box_w), height: rpx(box_h), marginTop: rpx(space), }}> <Image source={{uri: item.img}} style={{width: '100%', height: '100%', borderRadius: rpx(10)}} /> </TouchableOpacity> ); }; } 打包产品版apk

只有产品版的apk 才能分享给其它用户安装.

https://·/docs/signed-apk-android

添加 JAVA 的 bin 文件夹到 环境变量中

C:\Program Files\Java\jdk1.8.0_202\bin

win7: 双击之后把下方内容添加到 已有内容的末尾即可

;C:\Program Files\Java\jdk1.8.0_202\bin

在项目的 android/app 目录下生成秘钥, 执行下方命令行

如果提示 非内部 或 外部命令, 就是上方的 环境变量 没有正确添加

keytool -genkeypair -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

如果生成有问题的, 可以删除下方文件 再次生成即可!

桌面图标

从Android 9 开始, 真机必须使用 https 请求

必须人为设置: 允许 http 才可以!

打包命令: 必须在 项目的 android 目录下执行

gradlew assembleRelease

打包的apk 就可以发给其它人安装了

如果生成有问题的, 可以删除下方文件 再次生成即可!

桌面图标

从Android 9 开始, 真机必须使用 https 请求

必须人为设置: 允许 http 才可以!

打包命令: 必须在 项目的 android 目录下执行

gradlew assembleRelease

打包的apk 就可以发给其它人安装了


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #React05 #React05作业1 #斗鱼 #rncimport #React #component #from