Card
Card component
Klasičan redosled, prvo pravimo fajl Card.js unutar components direktorijuma i zatim pisemo standardan početni kod
import React from 'react';
import { View, Text } from 'react-native';
const Card = () => {
return (
<View></View>
);
};
export default Card;
Razlog postojanja ove komponente jeste da "samo bude lepa" i da obuhvati ostale komponente unutar nje. Zato krenimo odmah sa stilizovanjem iste.
const styles = {
cardStyle: {
borderWidth: 1,
borderRadius: 2,
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10
},
};
Mislim da nema potrebe previše objašnjavati ovaj styles objekat, princip je isti kao i pre, iz naziva property-ja je poprilično jasno šta rade, i još samo treba reći komponenti da koristi ovaj stil, a i to vam je poznato
const Card = () => {
const { cardStyle } = styles;
return (
<View style={ cardStyle }></View>
);
};
Sada iskoristimo ovu komponentu unutar BookDetail komponente tako što ćemo je prvo importovati
import Card from './Card';
A zatim zameniti je sa <View> tagom, jer želimo da nam ona bude "wrapper".
const BookDetail = (props) => {
return (
<Card>
<Text>{ props.book.title }</Text>
</Card>
);
};
Sada jedna bitna informacija. Pored props-a, koje parent komponenta može da prosledi child komponenti, mogu se proslediti i druge komponente, i to na ovaj gore ispisan način. Izmedju <Card> tagova nalazi se <Text> tag, ili ti komponenta. Svemu što se nalazi izmedju <Card> tagova, unutar Card komponente moguće je pristupiti kroz props.children
. Tako da malim izmenama unutar Card komponente možemo prikazati sve to unutar nje
const Card = (props) => {
const { cardStyle } = styles;
return (
<View style={ cardStyle }>
{ props.children }
</View>
);
};
Sada kada odradite reload simulatora, primetićete razdvojene kartice sa imenima knjiga
CardSection component
CardSection je jako slična Card komponenti, napravljena iz sličnih razloga (da bi se lakše stilizovala) i prikazuje sve što se nalazi izmedju njenih tagova.
import React from 'react';
import { View } from 'react-native';
const CardSection = (props) => {
const { cardSectionStyle } = styles;
return (
<View style={ cardSectionStyle }>
{ props.children }
</View>
);
};
const styles = {
cardSectionStyle: {
borderBottomWidth: 1,
padding: 5,
backgroundColor: '#fff',
justifyContent: 'flex-start',
flexDirection: 'row',
borderColor: '#ddd',
position: 'relative'
}
};
export default CardSection;
Iskoristimo je unutar CardDetail komponente, prvo importovanje
import CardSection './CardSection';
i zatim je postavimo oko <Text> taga
const BookDetail = (props) => {
return (
<Card>
<CardSection>
<Text>{ props.book.title }</Text>
</CardSection>
</Card>
);
};
Kada odradite reload simulatora, videćete blage izmene unutar Card komponenti.
Card Header
Vreme je da krenemo za radom na izgledu kartica. I prvo krećemo sa headerom. Ideja je da izgleda ovako:
Sa leve strane imaće sliku koja označava programski jezik koji knjiga objašnjava dok se sa desne strane nalazi ime knjige i ime autora. Dobra je praksa, zbog lakšeg rada, da se isplanira struktura. Da bi lakše pozicionirali ove elemente, levu i desnu stranu ćemo razdvojiti u dva <View> elementa koja ćemo koristeći flexbox mehanizam pozicionirati jedan pored drugog.
Fajl komponente BookDetail će izgledati ovako:
import React from 'react';
import { View, Text, Image } from 'react-native';
import Card from './Card';
import CardSection from './CardSection';
const BookDetail = ({ book }) => {
const { thumbnail, title, author } = book;
const {
headerTextContainerStyle,
thumbnailStyle,
thumbnailWrapperStyle,
titleStyle,
} = styles;
return (
<Card>
<CardSection>
<View style={ thumbnailWrapperStyle }>
<Image
style={ thumbnailStyle }
source={{ uri: thumbnail }}
/>
</View>
<View style={ headerTextContainerStyle }>
<Text style={ titleStyle }>{ title }</Text>
<Text>{ author }</Text>
</View>
</CardSection>
</Card>
);
};
const styles = {
headerTextContainerStyle: {
justifyContent: 'space-around',
flexDirection: 'column'
},
titleStyle: {
fontSize: 18,
},
thumbnailStyle: {
width: 50,
height: 50
},
thumbnailWrapperStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10,
}
};
export default BookDetail;
Prvo smo ubacili dva <View> taga, unutar prvog se nalazi nama novi tag <Image> koji ima property source koji prima objekat koji ima uri
koji predstavlja adresu do mesta slike koju želimo da prikažemo. Mi prikazujemo thumbnail iz data-e koju primamo. Možete videti da smo dodali stil tagu <Image> koji ima postavljenu width
i height
što je obavezno, jer za razliku od web <image> taga, React Native <Image> tag ne zauzima nikakvu automatksu visinu i širinu već se mora ručno postaviti.
Zatim smo <View> tagu koji okružuje taj <Image> tag dodali stil kojim smo centrirali sliku i stavili margine da bi napravili malo mesta između levih ivica i sa desne strane izmedju ivice i teksta.
Unutar drugog <View> imamo dva <Text> taga, jedan prikazuje naziv knjige a drugi ime pisca. Prvom <Text> tagu dodajemo stil koji samo uvećava veličinu fonta, dok <View> tagu koji okružuje taj tekst dobija headerTextContainerStyle
unutar koga koristimo flexDirection:'column'
kojim pozicioniramo <Text> tagove vertikalno, jedan ispod drugog, i justifyContent: 'space-around'
kojim se dobija razmaci kako izmedju <Text> tagova tako i izmedju njih i vrha i dna komponente.
Kada reload-ujete svoj simulator, header kartice već lepo izgleda.
Card Body
Unutar body-ja kartice želimo prikazati samo sliku knjige same knjige koja se nalazi unutar data-e sa informacijama o knjizi, tako da ćemo jednostavno ispod postojećeg <CardSection> staviti još jedan koji će sadržati <Image> tag koje će prikazivati našu sliku.
<CardSection>
<Image
style={ imageStyle }
source={{ uri: image }}
/>
</CardSection>
Stil koji dodajemo sadrži fiksnu visinu i flex property sa vrednosti 1 koji čini da se slika raširi celom širinom ekrana.
imageStyle: {
height: 300,
flex: 1
}
I tako dobijamo
I možemo učiti jedan "bug", iako znamo da postoji 5 knjiga koje naša aplikacija prikazuje mi ne možemo da ih vidimo jer ne možemo da "scroll"-ujemo na dole. To se rešava na jako jednostavan način jer je React Native već obezbedio tag <ScrollView>.
Prvo treba odrediti, koji element je potrebno skrolovati, u našem slučaju to je BookList, zato ćemo unutar fajla komponente BookList prvo importovati <ScrollView> a zatim ga u render metodi zameniti sa <View> tagom.
render() {
return (
<ScrollView>
{ this.renderBooks() }
</ScrollView>
);
}
Sada možete i scroll-ovati kroz vašu aplikaciju.
Card Button
Poslednja stavka u našoj aplikaciji jeste dugme koje će se nalaziti ispod slike knjige i koje će voditi na amazon stranicu gde se može kupiti knjiga. Napravićemo reusable komponentu koju ćemo menjati po našim potrebama.
Prvo krećemo od pravljenja novog fajla Button.js unutar components direktorijuma unutar koga pišemo kod
import React, { Component } from 'react';
import { Text } from 'react-native';
const Button = () => {
return (
<Text> Click me! </Text>
);
}
export default Button;
Import-ovaćemo Button komponentu unutar BookDetail komponente i ispod poslednje <CardSection> taga otvorićemo još jedan unutar koga ćemo smestiti Button.
<CardSection>
<Button />
</CardSection>
Kada reload-ujete simulator Button komponenta će se pojaviti ispod slike knjige, medjutim za sada je to samo tekst, i trebamo je stilizovati tako da korisnik kada klikne na nju ima neku povratnu informaciju o tome. U te svrhe React Native pruža više stvari kao izbor: TouchableOpacity.
Ovo četiri elementa predstavljaju ustvari Button elemente, koje koristimo kako bi pružili povratnu informaciju korisniku da je dugme pritisnuto i pored toga da bi handle-ovali odgovor na taj klik. Jedina razlika izmedju njih je u tome načinu na koji obaveštavaju korisnika da dugme pritisnuto.
Mi ćemo koristi TouchableOpacity, import-ovaćemo i njime ćemo okružiti <Text> element unutar Button komponente i zatim stilizovati komponentu
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = () => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity style={ buttonStyle }>
<Text style={ textStyle }> Click me! </Text>
</TouchableOpacity>
);
}
const styles = {
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export default Button;
Sada kada reload-ujete simulator i kliknete na Button komponentu biće vidljivijih i većih promena.
Još ostaje da postavimo neku vrstu "Event listener"-a koji će izvršavati odredjeni kod kada se dugme pritisne. To se ostvaruje korišćenjem onPress property-ja. Za početak stavimo console.log
da se izvršava na klik.
class Button extends Component {
render() {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={ () => console.log('Click!') } style={ buttonStyle }>
<Text style={ textStyle }> Click me! </Text>
</TouchableOpacity>
);
}
}
Nakon reload-a i klikna na bilo koje od dugmadi, ako proverite svoju konzolu videćete da se tekst "Click!" ispisuje
Kako bi učinili Button komponentu reusable-nom nećemo unutar nje pisati šta će se dešavati kada se dugme klikne već će tu funkciju kao i tekst koji će prikazivati dobijati kroz props-e od parent komponente gde je Button komponenta iskorišćena.
Pošto mi želimo da nas klik na dugme odvede sajt amazona (otvorite browser) gde se može kupiti knjiga, za to koristićemo biblioteku Linking koja zadovoljava našu potrebu
Unutar BookDetail komponente prvo ćemo import-ovati Linking
import { View, Text, Image, Linking } from 'react-native';
izlačimolink
koji nam je potreban iz book data-e koju smo primili
const { thumbnail, title, author, image, link } = book;
I na kraju našoj Button komponenti prosledjujemo funkciju kroz property onPress
(ovo možete nazvati kako god želite, ja zbog svoje logike nazivam isto) kao i text
property koji sadrži tekst će se prikazivati na Button komponenti.
<CardSection>
<Button onPress={ () => Linking.openURL(link) } text={ 'Buy now!' }/>
</CardSection>
I na kraju, Button komponenti "kažemo" da onPress
izvršava funkciju koju je putem props-a dobila od parent komponente koja se isto naziva onPress, i da postavimo željeni tekst.
const Button = ({ onPress, text }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={ onPress } style={ buttonStyle }>
<Text style={ textStyle }> { text } </Text>
</TouchableOpacity>
);
}
I na ovaj način završavamo i dobijamo potpuno reusable-nu komponentu koju možemo koristi na bilo kom mestu i bilo kojoj komponenti i jedino što je potrebno je da joj se prosledi onPress
i text
property i to je sve.
Ovim smo završili našu malu aplikaciju. Kada reload-ujete simulator klikom na Button otvoriće se browser i odvesti vas na amazon.com i to na stranu gde možete kupiti odabranu knjigu.
Izgled aplikacije
I browser na amazon strani nakon klika na dugme "Buy now!".
Ovim smo završili našu prvu aplikaciju Books.