类似美团筛选框实现的问题?(附图)



  • 0_1458808405476_1506849895.jpg

    点击好评优先,下面会弹出一层(并且是单选),请问这个实现的思路是什么?或者有组件做参考吗?谢谢各位!



  • 问题解决了没,坐等



  • 不需要动画

    不做动画的情况下,还是比较简单的,把单选视图和底层的遮罩视图放在一个view里面,然后设置这个view的初始位置,比如

           position:'absolute',
            top: this.state.top,// 屏幕高度的负值
            right: 0,
            left: 0,
            height: viewHeight,// 屏幕高度
    

    top值是「屏幕高度的负值」这样就可以让它不在屏幕中显示,然后点击button来改变this.state.top变成0就行了,另外单选或许可以参考react-native-tableview

    需要动画

    如果需要做动画,类似于这样的:

    alt text

    那么单选视图和底层的遮罩视图就需要放在两个view中,分别控制Y轴移动和渐变动画

    单选视图和前面一样,先放在一个不可见的地方,当时屏幕的上方,然后移动下来。遮罩视图就需要一开始就布局到屏幕内,并且设置透明度是0

    下面是简单例子

    /**
     * Sample React Native App
     * https://github.com/facebook/react-native
     */
    'use strict';
    import React, {
      AppRegistry,
      Component,
      StyleSheet,
      Text,
      View,
      ListView,
      Image,
      TouchableOpacity,
      NativeModules,
      Animated,
      Alert
    } from 'react-native';
    
    // import DetailRender from './DetailRender';
    // import SliderIOS from './Slider';
    
    // const Test = NativeModules.Test;
    
    const dismissDuration = 160
    
    class HomeRender extends Component {
      constructor(props) {
        super(props);
        this.state = {
          moveAnim: new Animated.Value(0),
          fadeAnim: new Animated.Value(0),
          maskTouchDisabled : true,
          pointerEvents: 'none'
        }
      }
    
    
      _otherAction() {
          const _this = this
          Animated.spring(
            this.state.moveAnim,
            {
              toValue: 1,
            },
          ).start();
    
          Animated.timing(
            this.state.fadeAnim,
            {
              toValue: 1,
            }
          ).start(()=>{
            _this.setState({
              maskTouchDisabled: false,
              pointerEvents: 'auto'
            });
          });
        }
    
        _otherAction() {
          const _this = this
          Animated.spring(
            this.state.moveAnim,
            {
              toValue: 1,
            },
          ).start();
    
          Animated.timing(
            this.state.fadeAnim,
            {
              toValue: 1,
            }
          ).start(()=>{
            _this.setState({
              maskTouchDisabled: false,
              pointerEvents: 'auto'
            });
          });
        }
    
        _otherView() {
        return(
          <Animated.View style={{
            backgroundColor: 'white',
            position:'absolute',
            bottom: 0,
            right: 0,
            left: 0,
            height: 216,
            transform: [{
              translateY: this.state.moveAnim.interpolate({
                inputRange: [0, 1],
                outputRange: [216, 0]
              }),
           }],
    
          }}>
    
          </Animated.View>
        )
      }
    
    
        _onPress() {
          Animated.timing(
            this.state.moveAnim,
            {
              toValue: 0,
              duration: dismissDuration
            },
          ).start();
    
          Animated.timing(
            this.state.fadeAnim,
            {
              toValue: 0,
              duration: dismissDuration
            }
          ).start(()=>{
            this.setState({
              maskTouchDisabled: true,
              pointerEvents: 'none'
            });
          });
        }
        _maskView() {
          return(
            <Animated.View style={{
              opacity: this.state.fadeAnim,
              backgroundColor: 'rgba(0,0,0,0.3)',
              position:'absolute',
              // flex:1,
              top:0,
              bottom:0,
              right:0,
              left:0
            }}
            pointerEvents={this.state.pointerEvents}
            >
            <TouchableOpacity
              disabled = {this.state.maskTouchDisabled}
              activeOpacity={1}
              onPress={() => this._onPress()}
              style={{flex:1}}>
              <View style={{flex:1}}>
              </View>
            </TouchableOpacity>
            </Animated.View>
          )
        }
    
        _otherAction() {
          const _this = this
          Animated.spring(
            this.state.moveAnim,
            {
              toValue: 1,
            },
          ).start();
    
          Animated.timing(
            this.state.fadeAnim,
            {
              toValue: 1,
            }
          ).start(()=>{
            _this.setState({
              maskTouchDisabled: false,
              pointerEvents: 'auto'
            });
          });
        }
    
    
      render() {
        const city = '上海';
        return (
          <View style={{flex:1,backgroundColor: 'yellow'}}>
            <TouchableOpacity
              onPress={() => {this._otherAction()}}
              style={{backgroundColor: 'black', width: 50, height: 50}}>
    
            </TouchableOpacity>
            {this._maskView()}
            {this._otherView()}
          </View>
        )
      }
    }
    
    const styles = StyleSheet.create({
      container: {
        flex: 1,
        backgroundColor: 'yellow',
        // alignItems: 'center',
        // justifyContent: 'center'
      },
      button: {
        // height: 40,
        // width: 60,
        backgroundColor: 'black',
        // justifyContent: 'center',
        // alignItems: 'center'
        flex: 1
      },
      animation: {
    
      }
    });
    
    module.exports = HomeRender;
    
    

    注意调整两个属性,pointerEvents={this.state.pointerEvents}disabled = {this.state.maskTouchDisabled}

    pointerEvents初始值必须是none,因为遮罩视图一开始就在视图内,如果不设置这个属性遮罩视图就会接收用户的操作,导致其他视图不响应,TouchableOpacity 的disabled也是同样的道理



  • @bawn 说:
    谢谢,我试试看。



  • 1、通过 onLayout 来判断浮动组件位置
    2、通过 Modal 来包含浮动组件

    如果通过一般 View 的话,在部分 TabBarIOS 包含的页面,会导致底栏无法覆盖



  • @郁也风 你好 modal会把页面全部覆盖 就不能再点击按钮关闭了 要怎么才能实现modal覆盖部分页面



  • @bcbclbc modal 是覆盖全屏的,你其实是要部分地方显示后面内容,这就可以用多个 view 来组合了, flexdirection: 'column', view 排列下来,需要遮罩的地方就把 view 改为半透明,需要点击关闭 modal,就给 view 增加点击操作,就可以了



  • @郁也风 嗯 谢谢


登录后回复