AplicaĆ§Ć£o Nuebank Front-end Mobile desenvolvida em React Native para clone da interface principal do app Nubank, voltada para bancos eletrĆ“nicos, empresas financiadoras e de crĆ©dito. O aplicativo permite a interaĆ§Ć£o do usuĆ”rio com o card principal com um simples gesto de arraste, permitindo poder visualizar o menu oculto.
- Components
- Routes
- react-navigation
- Axios
- Github API
- StatusBar
- gesture-handler
- PanGestureHandler
- States
- styled-components
- react-native-vector-icons
- react-native-webview-qrcode
- Animated
- npm install
- npm run start / npm start
- DĆŖ um fork nesse repositĆ³rio
- Crie a sua branch com a feature
- git checkout -b my-feature
- Commit a sua contribuiĆ§Ć£o
- git commit -m 'feat: My feature'
- Push a sua branch
- git push origin my-feature
import React from 'react';
import Icon from 'react-native-vector-icons/MaterialIcons';
import { Animated } from 'react-native';
import { PanGestureHandler, State }
from 'react-native-gesture-handler';
import Header from '~/components/Header';
import Tabs from '~/components/Tabs';
import Menu from '~/components/Menu';
import {
Container,
Content,
Card,
CardHeader,
CardContent,
CardFooter,
Title,
Description,
Annotation
} from './styles';
export default function Main() {
let offset = 0;
const translateY = new Animated.Value(0);
const animatedEvent = Animated.event(
[
{
nativeEvent: {
// Evento de arraste na vertical (eixo Y)
translationY: translateY,
}
}
],
{ useNativeDriver: true },
);
function onHandlerStateChange(event) {
// Se estado anterior Ć© ativo:
if (event.nativeEvent.oldState === State.ACTIVE) {
let opened = false;
const { translationY } = event.nativeEvent;
// Somar valor de cada arraste
offset += translationY;
if (translationY >= 88) {
opened = true;
} else {
translateY.setValue(0);
translateY.setOffset(offset);
offset = 0;
}
// AnimaĆ§Ć£o do limite de arraste
Animated.timing(translateY, {
toValue: opened ? 312 : 0,
duration: 200,
useNativeDriver: true,
}).start(() => {
offset = opened ? 312 : 0;
translateY.setOffset(offset);
// Reiniciar valor da variƔvel
translateY.setValue(0);
});
}
}
return (
<Container>
<Header />
<Content>
<Menu translateY={ translateY } />
<PanGestureHandler
onGestureEvent={ animatedEvent }
onHandlerStateChange={ onHandlerStateChange }
>
<Card style={{
transform: [{
// Arraste permitido
translateY: translateY.interpolate({
inputRange: [-500, 0, 312],
outputRange: [-50, 0, 312],
extrapolate: 'clamp'
}),
}]
}}>
<CardHeader>
<Icon
name="attach-money"
size={20}
color="#333"
/>
<Icon
name="visibility-off"
size={20}
color="#333"
/>
</CardHeader>
<CardContent>
<Title>Saldo disponĆvel</Title>
<Description>R$ 4.742,40</Description>
</CardContent>
<CardFooter>
<Annotation>
TransferĆŖncia de R$ 35,00 recebida
de Michele Cristina hoje Ć s 16:07h
</Annotation>
</CardFooter>
</Card>
</PanGestureHandler>
</Content>
<Tabs translateY={ translateY } />
</Container>
)
};
import React from 'react';
import Icon from 'react-native-vector-icons/MaterialIcons';
import logo from '~/assets/Nubank_Logo.png';
import
{
Container,
Top,
Logo,
Title
} from './styles';
export default function Header() {
return (
<Container>
<Top>
<Logo source={ logo } />
<Title>Renan</Title>
</Top>
<Icon
name="keyboard-arrow-down"
size={20}
color="#FFF"
/>
</Container>
);
};
import React from 'react';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {
Container,
TabsContainer,
TabItem,
TabText
} from './styles';
export default function Tabs({ translateY }) {
return (
<Container style={{
transform: [{
translateY: translateY.interpolate({
inputRange: [0,312],
outputRange: [0, 8],
extrapolate: 'clamp',
})
}],
// Efeito opacidade
opacity: translateY.interpolate({
inputRange: [0.01 , 312],
outputRange: [1, 0.3],
}),
}}
>
<TabsContainer>
<TabItem>
<Icon
name="person-add"
size={24}
color="#FFF"
/>
<TabText>Indicar amigos</TabText>
</TabItem>
<TabItem>
<Icon
name="chat-bubble-outline"
size={24}
color="#FFF"
/>
<TabText>Cobrar</TabText>
</TabItem>
<TabItem>
<Icon
name="arrow-downward"
size={24}
color="#FFF"
/>
<TabText>Depositar</TabText>
</TabItem>
<TabItem>
<Icon
name="arrow-upward"
size={24}
color="#FFF"
/>
<TabText>Transferir</TabText>
</TabItem>
<TabItem>
<Icon
name="lock"
size={24}
color="#FFF"
/>
<TabText>Bloquear</TabText>
</TabItem>
</TabsContainer>
</Container>
);
};
import React from 'react';
import QRCode from 'react-native-webview-qrcode';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {
Container,
Code,
Nav,
NavItem,
NavText,
SignOutButton,
SignOutButtonText
} from './styles';
export default function Menu({ translateY }) {
return (
<Container style={{
// Efeito opacidade
opacity: translateY.interpolate({
inputRange: [0, 150],
outputRange: [0, 1],
}),
}}>
<Code>
<QRCode
value="https://api.github.com"
size={80}
bgColor="#8B10AE"
fgColor="#FFF"
/>
</Code>
<Nav>
<NavItem>
<Icon
name="help-outline"
size={20}
color="#FFF"
/>
<NavText>Me ajuda</NavText>
</NavItem>
<NavItem>
<Icon
name="person-outline"
size={20}
color="#FFF"
/>
<NavText>Perfil</NavText>
</NavItem>
<NavItem>
<Icon
name="credit-card"
size={20}
color="#FFF"
/>
<NavText>Configurar cartĆ£o</NavText>
</NavItem>
<NavItem>
<Icon
name="smartphone"
size={20}
color="#FFF"
/>
<NavText>ConfiguraƧƵes do app</NavText>
</NavItem>
</Nav>
<SignOutButton onPress={() => {}}>
<SignOutButtonText>SAIR DO APP</SignOutButtonText>
</SignOutButton>
</Container>
);
};