React05

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://www.reactnative.cn/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 就可以发给其它人安装了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值