Skip to content

tsaohucn/react-native-comic-book

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

80 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

react-native-comic-book

Installation

  1. Runnpm install git+http://192.168.0.200/xc/react-native-comic-book.git --save

  2. react-native-comic-book use some native library so that you have to link those library below before you use react-native-comic-book

    react-native link react-native-vector-icons

    react-native link react-native-screen-brightness

    react-native link react-native-gesture-handler

  3. Open your MainActivity.java to change the code to below

    import com.facebook.react.ReactActivityDelegate;
    import com.facebook.react.ReactRootView;
    import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
    
    public class MainActivity extends ReactActivity {
    
      // Add the following method to your main activity class
      @Override
      protected ReactActivityDelegate createReactActivityDelegate() {
        return new ReactActivityDelegate(this, getMainComponentName()) {
          @Override
          protected ReactRootView createRootView() {
            return new RNGestureHandlerEnabledRootView(MainActivity.this);
          }
        };
      }
    }
  4. Open your MainApplication.java to change the code to below

      new ScreenBrightnessPackage(1)

API

Props Description Type Default
onClickBackArrow Fired after you click back-arrow icon function none
onEndComicBook Fired after end of your comic-book function none
noPreviousChapter Fired when you click PreviousChapter button but there's no any previous chapter function none
noNextChapter Fired when you click NextChapter button but there's no any next chapter function none
noPreviousPageNumber Fired when you click TopArea to page up but it's alerady in the first page with no previous page function none
noNextPageNumber Fired when you click BottomArea to page down but it's alerady in the last page with no next page function none
initialPageNumber Initial page number of your comic-book Integer 1
chapter Chapter structure of your comic-book Array[object] []
content Content of your comic-book Array[object] []
renderContentrequired How to render your content function none
getContentLayoutrequired Layout of your content function none

Array[object]

  • chapter : [{ pageNumber: (Int)(Reuired)(Unique), title: (String)(Option) }]

    • pageNumber : pageNumber of this chapter
    • title : title of this chapter
  • content : [{ key: (String)(Reuired)(Unique), ...other }]

    • key : unique string key
    • ...other : It depends on your renderContent function that how do you render your each item

Remember custom your renderContent and getContentLayout at same time

  • The props as same as renderItem getItemLayout of FlatList
renderContent = ({ item, index }) => {
  // return your content render
}

getContentLayout = (data, index) => { 
  // return your content layout
  if (index >= 0) {
    return { length: `your item length of this index`, offset: `your item offset of this index`, index }
  } else {
    return { length: 0, offset: 0, index } 
    // Add this line because initialPageNumber will cause index < 0 bug now
    // https://github.com/facebook/react-native/issues/18743
  }
}

Usage example

  • Novel
import React, { Component } from 'react'
import { 
  View, 
  Text,
  Button,
  Dimensions
} from 'react-native'
import { StackNavigator } from 'react-navigation'
import getSlideFromRightTransition from 'react-navigation-slide-from-right-transition'
import ComicBook from 'react-native-comic-book'

class HomeScreen extends Component {
  render() {
    return (
      <View style={styles.home}>
        <Text>Home</Text>
        <Button
          title="Go To ComicBook"
          onPress={() => this.props.navigation.navigate('ComicBook')}
        />
      </View>
    );
  }
}

class ComicBookScreen extends Component {

  constructor(props) {
    super(props)
  }

  onEndComicBook = (pageNumber) =>  {
    console.log(pageNumber)
  }

  onClickBackArrow = () => {
    this.props.navigation.goBack()
  }

  noPreviousChapter = () => {
    console.log('沒有上一回')
  }

  noNextChapter = () => {
    console.log('沒有下一回')
  }

  noPreviousPageNumber = () => {
    console.log('沒有上一頁')
  }

  noNextPageNumber = () => {
    console.log('沒有下一頁')
  }

  renderContent = ({ item, index }) => 
    <View style={styles.content}>
      <View style={styles.pageNumber}>
        <Text>{index + 1}</Text>
      </View>
      <View style={styles.novel}>
        <Text>{item.novel}</Text>
      </View>
    </View>

  getContentLayout = (data, index) => ({ length: 500, offset: 500*index, index })

  render() {
    return (
      <ComicBook
        onClickBackArrow={this.onClickBackArrow}
        onEndComicBook={this.onEndComicBook}
        noPreviousChapter={this.noPreviousChapter}
        noNextChapter={this.noNextChapter}
        noPreviousPageNumber={this.noPreviousPageNumber}
        noNextPageNumber={this.noNextPageNumber}
        content={content}
        renderContent={this.renderContent}
        getContentLayout={this.getContentLayout}
        initialPageNumber={30}
        chapter={chapter}
      />
    );
  }
}

export default class App extends React.Component {
  render() {
    return <RootStack />
  }
}

const RootStack = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    ComicBook: {
      screen: ComicBookScreen,
    }
  },
  {
    initialRouteName: 'Home',
    headerMode: 'none',
    transitionConfig: getSlideFromRightTransition
  }
)

const content = Array(100).fill().map((e,index) => ({
  key: index.toString(),
  novel: '你的小說內容'
}))

const chapter = [
  { pageNumber: 76, title: '戰役' },
  { pageNumber: 5, title: '精氣' },
  { pageNumber: 29, title: '鎮寢之寶' },
  { pageNumber: 16, title: '夢中人' },
  { pageNumber: 39, title: '飛來豔福' },
  { pageNumber: 26, title: '馬克思主義哲學' },
  { pageNumber: 69, title: '演員的自我修飾' },
  { pageNumber: 48, title: '天降之物' },
  { pageNumber: 95, title: '亞拉那一卡?' },
  { pageNumber: 89, title: '相遇' }
]

const styles = { 
  home: {
    flex: 1, 
    justifyContent: 'center',
    alignItems: 'center'
  },
  content: {
    backgroundColor: 'white', 
    height: 500
  },
  pageNumber: {
    flex: 1
  },
  novel: {
    flex: 1,
    justifyContent: 'flex-start',
    alignItems: 'center'
  } 
}
  • ComicBook
import React, { Component } from 'react'
import { 
  View, 
  Text,
  Image,
  Button,
  Dimensions,
  ActivityIndicator
} from 'react-native'
import { StackNavigator } from 'react-navigation'
import getSlideFromRightTransition from 'react-navigation-slide-from-right-transition'
import ComicBook from 'react-native-comic-book'
import LoadingImage from './LoadingImage'

class HomeScreen extends Component {
  render() {
    return (
      <View style={styles.home}>
        <Text>Home</Text>
        <Button
          title="Go To ComicBook"
          onPress={() => this.props.navigation.navigate('ComicBook')}
        />
      </View>
    );
  }
}

class ComicBookScreen extends Component {

  constructor(props) {
    super(props)
    this.length = new Array
    this.offset = new Array
    this.state = {
      isLoading: true
    }
  }

  componentDidMount() {
    // this part may exist some issue on ios now
    // https://github.com/facebook/react-native/pull/18875
    const scaleImageHeightPromise = content.map(async (ele,index) => {
      let scaleImageHeight = width
      await Image.getSize(ele.uri,(imageWidth, imageHeight) => {
        if (imageWidth && imageHeight) {
          scaleImageHeight = width*imageHeight/imageWidth
          console.log(scaleImageHeight)
        }
      },() => {
        scaleImageHeight = width
      })
      return scaleImageHeight
    })
    
    Promise.all(scaleImageHeightPromise).then(value => {
      this.length = value
      let offset = 0
      this.offset = this.length.map(lenght => {
        offset += lenght
        return offset
      })
      this.offset.unshift(0)
      this.setState({
        isLoading: false
      })
    }).catch(err => {
      alert(err)
    })
  }

  onEndComicBook = (pageNumber) =>  {
    console.log(pageNumber)
  }

  onClickBackArrow = () => {
    this.props.navigation.goBack()
  }

  noPreviousChapter = () => {
    console.log('沒有上一回')
  }

  noNextChapter = () => {
    console.log('沒有下一回')
  }

  noPreviousPageNumber = () => {
    console.log('沒有上一頁')
  }

  noNextPageNumber = () => {
    console.log('沒有下一頁')
  }

  renderContent = ({ item, index }) => 
    <LoadingImage
      width={width}
      height={this.length[index]}
      source={{uri: item.uri}}
    />

  getContentLayout = (data, index) => {
    if (index >= 0) {
      return { length: this.length[index], offset: this.offset[index], index }
    } else {
      return { length: 0, offset: 0, index } 
      // Add this line because initialPageNumber will cause index < 0 bug now
      // https://github.com/facebook/react-native/issues/18743
    }
  }

  render() {
    return (
      <View style={styles.comicbook}>
        {
          this.state.isLoading ? 
          <ActivityIndicator
            style={styles.activityIndicator}
            size={'large'}
            color={'white'}
          /> :
          <ComicBook
            onClickBackArrow={this.onClickBackArrow}
            onEndComicBook={this.onEndComicBook}
            noPreviousChapter={this.noPreviousChapter}
            noNextChapter={this.noNextChapter}
            noPreviousPageNumber={this.noPreviousPageNumber}
            noNextPageNumber={this.noNextPageNumber}
            content={content}
            renderContent={this.renderContent}
            getContentLayout={this.getContentLayout}
            initialPageNumber={5}
            chapter={chapter}
          />
        }
      </View>
    )
  }
}

export default class App extends React.Component {
  render() {
    return <RootStack />
  }
}

const RootStack = StackNavigator(
  {
    Home: {
      screen: HomeScreen,
    },
    ComicBook: {
      screen: ComicBookScreen,
    }
  },
  {
    initialRouteName: 'Home',
    headerMode: 'none',
    transitionConfig: getSlideFromRightTransition
  }
)

const { width, heigth } = Dimensions.get("window")

const content = Array(500).fill().map((e,index) => {

  const randomWidth = getRandomArbitrary(200,500).toFixed(0)
  const randomHeight = getRandomArbitrary(200,500).toFixed(0)

  return({ 
    key: index.toString(),
    uri: 'https://via.placeholder.com/' + randomWidth + 'x' + randomHeight
    //uri: 'https://picsum.photos/'+ randomWidth + '/' + randomHeight + '?image=' + index,
  })
})

const chapter = [
  { pageNumber: 20, title: '戰役' },
  { pageNumber: 133, title: '精氣' },
  { pageNumber: 100, title: '鎮寢之寶' },
  { pageNumber: 93, title: '夢中人' },
  { pageNumber: 45, title: '飛來豔福' },
  { pageNumber: 198, title: '馬克思主義哲學' },
  { pageNumber: 267, title: '演員的自我修飾' },
  { pageNumber: 356, title: '天降之物' },
  { pageNumber: 462, title: '亞拉那一卡?' },
  { pageNumber: 410, title: '相遇' }
]

const styles = { 
  home: {
    flex: 1, 
    justifyContent: 'center',
    alignItems: 'center'
  },
  comicbook: {
    flex: 1,
    backgroundColor: '#000000'
  },
  activityIndicator: {
    flex: 1,
    justifyContent: 'center'
  }
}

function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}