skip to Main Content

I want to create a see-more text that takes number an initial number of lines, and if the text needs more space it shows View more/less.

like this image:

enter image description here

enter image description here

I tried most of the solutions on stackoverflow but non of them work on ios.

2

Answers


  1. Chosen as BEST ANSWER

    Here is the code that works for me, thanks to react-native-read-more-text library for the ios hack:

    import React, { useState } from "react";
    import {
      NativeSyntheticEvent,
      Platform,
      StyleSheet,
      Text,
      TextLayoutEventData,
      TouchableOpacity,
    } from "react-native";
    
    interface ViewMoreTextProps {
      text: string;
      initialVisibleLines: number;
    }
    
    const ViewMoreText: React.FC<ViewMoreTextProps> = ({
      text,
      initialVisibleLines,
    }) => {
      const styles = useStyles();
    
      const [isExpanded, setIsExpanded] = useState(false);
      const [shouldShowMore, setShouldShowMore] = useState(false);
      const numberOfLines = isExpanded ? undefined : initialVisibleLines;
    
      const toggleExpanded = () => setIsExpanded(!isExpanded);
    
      const isAndroid = Platform.OS === "android";
      const isiOS = Platform.OS === "ios";
    
      return (
        <>
          {isiOS && (
            <Text
              style={styles.bodyText && { height: 0 }}
              onTextLayout={(e: NativeSyntheticEvent<TextLayoutEventData>) => {
                if (isiOS) {
                  console.log("ios lines: " + e.nativeEvent.lines.length);
                  setShouldShowMore(
                    e.nativeEvent.lines.length > initialVisibleLines
                  );
                }
              }}
            >
              {text || ""}
            </Text>
          )}
          <Text
            style={styles.bodyText}
            numberOfLines={numberOfLines}
            onTextLayout={(e: NativeSyntheticEvent<TextLayoutEventData>) => {
              if (isAndroid) {
                console.log("android lines: " + e.nativeEvent.lines.length);
                setShouldShowMore(e.nativeEvent.lines.length > initialVisibleLines);
              }
            }}
          >
            {text || ""}
          </Text>
          {shouldShowMore && (
            <TouchableOpacity
              style={styles.viewMoreContainer}
              onPress={toggleExpanded}
            >
              <Text style={styles.viewMoreText}>
                {isExpanded ? "View less" : "View more"}
              </Text>
            </TouchableOpacity>
          )}
        </>
      );
    };
    
    const useStyles = () => {
      return StyleSheet.create({
        headerRow: {
          flexDirection: "row",
          justifyContent: "space-between",
        },
        container: {
          paddingBottom: 10,
          marginTop: 10,
          marginRight: 10,
          marginLeft: 10,
          borderBottomWidth: 1,
          borderBottomColor: "#000",
        },
        title: {
          fontWeight: "bold",
        },
        abnormalFlagContainer: {
          backgroundColor: "#f00",
          borderRadius: 5,
          paddingHorizontal: 10,
          paddingVertical: 5,
          marginTop: 10,
          alignSelf: "flex-start",
        },
        abnormalFlagText: {
          fontWeight: "bold",
          color: "#f00",
        },
        normalRange: {
          marginTop: 10,
          color: "#000",
        },
        bodyText: {
          color: "#000",
          marginTop: 10,
        },
        viewMoreContainer: {
          flexDirection: "row",
          alignItems: "center",
          marginTop: 10,
          alignSelf: "flex-start",
        },
        viewMoreText: {
          marginRight: 5,
          borderBottomWidth: 1,
        },
      });
    };
    
    export default ViewMoreText;
    

    Example:

    <ViewMoreText
      text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
    initialVisibleLines={3}
    />
    

    Android:

    enter image description here

    enter image description here iOS:

    enter image description here

    enter image description here


  2. Here just use mine collapse component

    import React, { useEffect, useState } from 'react';
    import { CSSTransition } from 'react-transition-group';
    
    export default function Collapse({ title, children, defaultValue }) {
        const [isOpen, setIsOpen] = useState(defaultValue);
    
        return (
            <div className="border border-gray-200 rounded-lg mb-4">
                <div
                    className="flex justify-between items-center cursor-pointer px-4 py-2"
                    onClick={() => setIsOpen(!isOpen)}
                >
                    <div>{title}</div>
                    <div>
                        {isOpen ? (
                            <svg
                                xmlns="http://www.w3.org/2000/svg"
                                className="h-6 w-6"
                                fill="none"
                                viewBox="0 0 24 24"
                                stroke="currentColor"
                            >
                                <path
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                    strokeWidth={2}
                                    d="M5 15l7-7 7 7"
                                />
                            </svg>
                        ) : (
                            
                            <svg
                                xmlns="http://www.w3.org/2000/svg"
                                className="h-6 w-6"
                                fill="none"
                                viewBox="0 0 24 24"
                                stroke="currentColor"
                            >
                                <path
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                    strokeWidth={2}
                                    d="M19 9l-7 7-7-7"
                                />
                            </svg>
                        )}
                    </div>
                </div>
                <CSSTransition in={isOpen} timeout={200} classNames="collapse" unmountOnExit>
                    <div className="p-4 border-t border-gray-200">{children}</div>
                </CSSTransition>
            </div>
        );
    }
    

    Here is the explainiton this code:

    You are creating a state that named isOpen or anything
    Using svg for arrows and controlled by isOpen state
    And contnet box with animation also controlled by isOpen

    you must install this package

    npm i react-transition-group

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search