柔性箱动态宽度和高度

时间:2015-07-04 21:51:21

标签: flexbox react-native

我正在尝试使用react-native例如:

创建消息视图

enter image description here

如你所见:

  1. 根据内容
  2. ,气泡具有动态宽度和高度
  3. 气泡有一个最大宽度,它们向下生长
  4. 我正在尝试使用本机重新创建它,但是我只能实现(2)并且不确定如何实现两者的效果......这就是我到目前为止所拥有的:

    enter image description here

      <View style={{flex:1,backgroundColor:'blue',flexDirection:'row'}}>
         <View style={{backgroundColor:'orange'}}>
                <View style={{width:90,flex:1}}>
                  <Text>123</Text>
                  </View>
         </View>
         <View style={{flex:0.25,backgroundColor:'red'}}>
                  <Text>123</Text>
         </View>
      </View>
    

    如果我增加橙色视图来表示一个大泡泡,那么它就会离开屏幕......例如:

    enter image description here

5 个答案:

答案 0 :(得分:15)

我遇到了同样的问题。我尝试了很多东西,包括在这里放置包装(如前面的答案所述)。他们都没有工作。

@AndréJunges的回答是不正确的,因为@kingkong和我有不同的要求。

然后,我看到flex也可以取值-1。并设置它解决了问题。

以下是代码:

const messages = [
              'hello',
              'this is supposed to be a bit of a long line.',
              'bye'
              ];
return (
  <View style={{
            position: 'absolute',
            top: 0,
            left: 0,
            width: 150,
            alignItems: 'flex-end',
            justifyContent: 'flex-start',
            backgroundColor: '#fff',
            }}>

{messages.map( (message, index) => (
  <View key={index} style={{
                  flexDirection: 'row',
                  marginTop: 10
                }}>
    <View style={{
                  flex: -1,
                  marginLeft: 5,
                  marginRight: 5,
                  backgroundColor: '#CCC',
                  borderRadius: 10,
                  padding: 5,
                }}>
      <Text style={{
                    fontSize: 12,
                    }}>
        {message}
      </Text>
    </View>
    <Image source={require('some_path')} style={{width:30,height:30}} />
   </View> 
  ))} 
 </View>
)

结果如下:

And here is the result:

答案 1 :(得分:4)

我想出了一个有点人为的做法。我们先来看一下这个问题。

我们可以使用flexbox将“徽章”放在左侧,将文本放在右侧,然后将“消息行”水平放下。这很容易,但我们想要的是消息行根据其内容改变宽度,并且flexbox不会让你这样做,因为它贪婪地扩展以填充所有空间。

我们需要的是一种检查消息文本宽度的方法,然后相应地调整视图大小,将其强制为指定的宽度。我们不能使用measure来获取文本宽度,因为它实际上只给出了底层节点的宽度,而不是实际的文本本身。

为了做到这一点,我偷了一个想法from here并创建了一个与Obj-C的桥梁,它创建了一个带有文本的UILabel并以此方式获得它的宽度。

//  TextMeasurer.h
#import "RCTBridgeModule.h"
#import <UIKit/UIKit.h>

@interface TextMeasurer : NSObject<RCTBridgeModule>

@end


//  TextMeasurer.m
#import "TextMeasurer.h"

@implementation TextMeasurer

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(get:(NSString *)text cb:(RCTResponseSenderBlock)callback)
{
  UILabel *label = [[UILabel alloc]init];
  label.font = [UIFont fontWithName:@"Helvetica" size:14.0];
  label.text = text;

  callback(@[[NSNumber numberWithDouble: label.intrinsicContentSize.width]]);
}

@end

然后我把它的用法包装成一个组件:

var AutosizingText = React.createClass({
    getInitialState: function() {
        return {
            width: null
        }
    },

    componentDidMount() {
        setTimeout(() => {
            this.refs.view.measure((x, y, width, height) => {
                TextMeasurer.get(this.props.children, len => {
                    if(len < width) {
                        this.setState({
                            width: len
                        });
                    }
                })
            });
        });
    },

    render() {
        return <View ref="view" style={{backgroundColor: 'red', width: this.state.width}}><Text ref="text">{this.props.children}</Text></View>
    }
});

如果文本的宽度小于视图的原始宽度(这将由flexbox设置),所有这一切都将调整包含视图的大小。应用程序的其余部分如下所示:

var messages = React.createClass({
    render: function() {
        var rows = [
            'Message Text',
            'Message Text with lots of content ',
            'Message Text with lots of content put in here ok yeah? Keep on talking bla bla bla whatever is needed to stretch this message body out.',
            'Keep on talking bla bla bla whatever is needed to stretch this message body out.'
        ].map((text, idx) => {
            return <View style={styles.messageRow}>
                <View style={styles.badge}><Text>Me</Text></View>
                <View style={styles.messageOuter}><AutosizingText>{text}</AutosizingText></View>
            </View>
        });

        return (
            <View style={styles.container}>
                {rows}
            </View>
        );
    }
});

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'stretch',
    flexDirection: 'column',
    backgroundColor: '#F5FCFF',
  },
  messageRow: {
    flexDirection: 'row',
    margin: 10
  },
  badge: {
    backgroundColor: '#eee',
    width: 80, height: 50
  },
  messageOuter: {
    flex: 1,
    marginLeft: 10
  },
  messageText: {
    backgroundColor: '#E0F6FF'
  }
});

AppRegistry.registerComponent('messages', () => messages);

它给你这个:

enter image description here

我会密切关注Github issue,因为这个解决方案肯定有点笨拙,至少我希望在某些时候看到更好的方法来测量RN中的文本。

答案 2 :(得分:2)

我知道这个问题来自一年前,但我遇到了类似的问题,我认为这对其他开发者有用。

所以我想要实现的是创建如下图所示的框,左边有一个文本,右边有一个箭头。
请注意,这些框应具有routes高度 - 因为文本可以是多行..

enter image description here

JSX

auto

样式

<View style={styles.container}>
  <View style={styles.textContainer}>
    <Text style={styles.text}>{props.message.text}</Text>
  </View>
  <View style={styles.iconContainer}>
    <Icon name="chevron-right" size={30} color="#999" />
  </View>
</View>

当然,它没有用。出于某种原因,如果我的父母有container: { flex: 1, flexDirection: 'row', alignItems: 'center', backgroundColor: '#FFF', marginBottom: Metrics.baseMargin, borderRadius: 3, }, textContainer: { flex: 1, flexDirection: 'column', paddingVertical: 30, paddingHorizontal: Metrics.doubleBaseMargin, }, text: { color: '#333', }, iconContainer: { width: 35, borderLeftWidth: 1, borderLeftColor: '#ddd', justifyContent: 'center', alignItems: 'center', alignSelf: 'stretch', }, ,那么孩子就不会成长。 文字被包裹在多行中,但父亲的身高(flexDirection: 'row')并未增长 - 在某些情况下,文字甚至会在容器外显示。您可以在下图中看到它(第三条消息)。

enter image description here

修复是用另外一个.textContainer包装整个组件,如下面的代码所示:

View

<View style={styles.wrapper}> <View style={styles.container}> <View style={styles.textContainer}> <Text style={styles.text}>{props.message.text}</Text> </View> <View style={styles.iconContainer}> <Icon name="chevron-right" size={30} color="#999" /> </View> </View> </View> 类只有样式详细信息(从.wrapper移动)

.container

答案 3 :(得分:1)

所以我认为这里的策略是你想在整个宽度块中包含消息气泡,然后有两个内部视图。一个内部视图试图尽可能地薄,这是你放入文本的那个。另一个试图尽可能宽,从而将另一个块压缩得足够宽以包含文本。

<View style={{flex:1,backgroundColor:'blue',flexDirection:'row'}}>
  <View style={{flex:0,backgroundColor:'red'}}>
    <Text>123</Text>
  </View>
  <View style={{backgroundColor:'orange', flex: 1}}/> 
</View>

答案 4 :(得分:0)

按照编码可能没有用。 但似乎它不适用于动态内容,仅适用于静态内容...