Related
I have built an animated search bar in react native just like search bar of facebook mobile application. The search bar opens up when the search button is clicked on the header. It currently takes same height as the custom header that it is being rendered on. But i want to increase the height of the header to half the screen size when the search bar is on focus and set the height to default when the search bar is not focused. I have tried using my own logic but the problem was when i increased the height the contents of headers were shown below the search bar. And i dont want that. Can anyone help me how to resolve this?
/* eslint-disable #typescript-eslint/no-unused-vars */
import React, {useContext, useRef} from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
SafeAreaView,
Animated,
TextInput,
Easing,
} from 'react-native';
import Logo from '#assets/images/NCLogo.png';
import Colors from '#constants/colors/colors';
import Search from '#assets/icons/Search.svg';
import Back from '#assets/icons/back-arrow.svg';
import {AuthContext} from '#components/ContextStore/AuthContext/AuthContext';
import DateAndDayGenerator from '#utils/DayGen';
import {HEIGHT, WIDTH} from '#utils/Dimensions';
import Metrics from '#constants/metrics/Metrics';
import Fonts from '#constants/fonts/fonts';
import SearchList from '#components/ListNews/SearchList';
interface Props {
news?: any;
}
const Header: React.FC<Props> = () => {
const date = new Date();
const dateAndDay = DateAndDayGenerator(date);
const {color} = useContext(AuthContext);
const [focused, setFocused] = React.useState(false);
const [value, setValue] = React.useState('');
const inputRef = useRef<TextInput>(null);
// animation initial value
const inputTranslateX = useRef(new Animated.Value(WIDTH)).current;
const backButtonOpacity = useRef(new Animated.Value(0)).current;
const contentTranslateY = useRef(new Animated.Value(HEIGHT)).current;
const contentOpacity = useRef(new Animated.Value(0)).current;
const handleClear = () => {
setValue('');
};
const handleBlur = () => {
setFocused(false);
const inputTranslateXConfig = {
toValue: WIDTH,
duration: 200,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const backButtonOpacityConfig = {
toValue: 0,
duration: 50,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const contentTranslateYConfig = {
toValue: HEIGHT,
duration: 0,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const contentOpacityConfig = {
toValue: 0,
duration: 200,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
Animated.parallel([
Animated.timing(inputTranslateX, inputTranslateXConfig),
Animated.timing(backButtonOpacity, backButtonOpacityConfig),
Animated.timing(contentTranslateY, contentTranslateYConfig),
Animated.timing(contentOpacity, contentOpacityConfig),
]).start();
inputRef.current?.blur();
};
const handleFocus = () => {
setFocused(true);
const inputTranslateXConfig = {
toValue: 0,
duration: 200,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const backButtonOpacityConfig = {
toValue: 1,
duration: 200,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const contentTranslateYConfig = {
toValue: 0,
duration: 0,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
const contentOpacityConfig = {
toValue: 1,
duration: 200,
useNativeDriver: true,
easing: Easing.inOut(Easing.ease),
};
Animated.parallel([
Animated.timing(inputTranslateX, inputTranslateXConfig),
Animated.timing(backButtonOpacity, backButtonOpacityConfig),
Animated.timing(contentTranslateY, contentTranslateYConfig),
Animated.timing(contentOpacity, contentOpacityConfig),
]).start();
inputRef.current?.focus();
};
return (
<>
<SafeAreaView style={styles.header_safe}>
<View style={styles.header}>
<View style={styles.view}>
<View style={styles.Logo}>
<Image source={Logo} style={styles.image} />
</View>
{color ? (
<View style={styles.texts}>
<Text style={[styles.text, {color}]}>Nepali Congress</Text>
<Text style={styles.date}>{`${dateAndDay.day}, ${
dateAndDay.month
} ${dateAndDay.date},${' '}${dateAndDay.year}`}</Text>
</View>
) : (
<View style={styles.texts}>
<Text style={styles.text}>Nepali Congress</Text>
<Text style={styles.date}>{`${dateAndDay.day}, ${
dateAndDay.month
} ${dateAndDay.date},${' '}${dateAndDay.year}`}</Text>
</View>
)}
<TouchableOpacity onPress={handleFocus}>
<View style={styles.search}>
<Search width={25} height={25} fill="none" />
</View>
</TouchableOpacity>
<Animated.View
style={[
styles.input,
{transform: [{translateX: inputTranslateX}]},
]}>
<Animated.View style={{opacity: backButtonOpacity}}>
<TouchableOpacity
activeOpacity={1}
style={styles.back_icon}
onPress={handleBlur}>
<Back width={28} height={28} fill="#000" />
</TouchableOpacity>
</Animated.View>
<TextInput
ref={inputRef}
placeholder="Enter title, description or date of news"
placeholderTextColor="#000"
clearButtonMode="while-editing"
onFocus={handleFocus}
value={value}
onChangeText={text => {
setValue(text);
}}
style={styles.input_text}
/>
<TouchableOpacity
onPress={handleClear}
style={styles.clearButton}>
<Text style={styles.clear}>X</Text>
</TouchableOpacity>
</Animated.View>
</View>
</View>
</SafeAreaView>
<Animated.View
style={[
styles.content,
{
opacity: contentOpacity,
transform: [{translateY: contentTranslateY}],
},
]}>
<SafeAreaView style={styles.content_safe}>
<View style={styles.content_inner}>
<View style={styles.separator} />
<SearchList searchPhrase={value} />
</View>
</SafeAreaView>
</Animated.View>
</>
);
};
const styles = StyleSheet.create({
header_safe: {
zIndex: 1000,
},
header: {
height: HEIGHT * 0.087,
paddingHorizontal: 16,
backgroundColor: Colors.white,
},
view: {
flex: 1,
overflow: 'hidden',
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
position: 'relative',
},
Logo: {
margin: 10,
alignItems: 'center',
flexDirection: 'row',
width: WIDTH * 0.15,
height: HEIGHT * 0.055,
},
image: {
width: '100%',
height: '100%',
resizeMode: 'stretch',
},
texts: {
marginLeft: 4,
marginRight: WIDTH * 0.155,
},
text: {
fontSize: Metrics.h3,
color: Colors.black,
fontFamily: Fonts.type.montBold,
width: WIDTH * 0.5,
},
date: {
marginTop: 4,
fontSize: Metrics.body7,
color: Colors.black,
fontFamily: 'Mont-Regular',
},
search: {
width: 35,
height: 35,
right: 20,
borderRadius: 80,
backgroundColor: '#f5f5f5',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
input: {
height: HEIGHT * 0.087,
flexDirection: 'row',
alignItems: 'center',
position: 'absolute',
top: 0,
left: 0,
backgroundColor: Colors.white,
width: WIDTH - 32,
},
back_icon: {
width: 40,
height: 40,
borderRadius: 40,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginRight: 5,
transform: [{rotate: '180deg'}],
},
input_text: {
flex: 1,
height: 37,
backgroundColor: '#e4e6e8',
borderRadius: 80,
paddingHorizontal: 16,
fontSize: 13,
color: Colors.black,
},
input_text1: {
flex: 1,
height: 37,
backgroundColor: '#e4e6e8',
borderRadius: 80,
paddingHorizontal: 16,
fontSize: 13,
},
content: {
position: 'absolute',
width: WIDTH,
height: HEIGHT,
left: 0,
bottom: 0,
zIndex: 999,
},
content_safe: {
flex: 1,
backgroundColor: Colors.white,
},
content_inner: {
flex: 1,
paddingTop: HEIGHT * 0.087,
},
separator: {
height: 1,
marginTop: 5,
backgroundColor: '#e6e4eb',
},
search_results: {
alignItems: 'center',
borderBottomWidth: 1,
borderBottomColor: '#e6e4eb',
marginLeft: 16,
},
clearButton: {
width: 30,
height: 30,
borderRadius: 80,
marginLeft: 10,
backgroundColor: Colors.red,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
clear: {
fontSize: 14,
color: Colors.black,
fontWeight: 'bold',
},
});
export default Header;
iPad size
iPhone size
Im having trouble with sizing for iPad and other tablets with the Carousel. Im stuck on how to properly get both devices to look the same. I figured that the scaling is stuck on certain dimensions for the carousel and it scales with it to make it bigger. I just don't know how to adjust them for a different screen.
const ITEM_WIDTH = Math.round(SLIDER_WIDTH * 0.8); //was 0.85
this line scales the flashcard. I need it to scale with the device screen dimensions
import React, { Component } from "react";
import {
ImageBackground,
Text,
View,
Image,
Dimensions,
StyleSheet,
Pressable,
SafeAreaView,
} from "react-native";
import Carousel from "react-native-snap-carousel";
import { Pagination } from "react-native-snap-carousel";
import { scrollInterpolator, animatedStyles } from "./utils/animations";
const SLIDER_WIDTH = Dimensions.get("window").width;
const SLIDER_HEIGHT = Dimensions.get("window").height;
const ITEM_WIDTH = Math.round(SLIDER_WIDTH * 0.8); //was 0.85
const ITEM_HEIGHT = Math.round((ITEM_WIDTH * 6) / 4);
export default class App extends Component {
constructor(props) {
super(props);
this._renderItem = this._renderItem.bind(this);
}
_renderItem({ item }) {
return (
<View style={styles.itemContainer}>
<Pressable onPress={() => this.props.navigation.navigate(item.key)}>
<View style={styles.itemFlashcard}>
<ImageBackground
source={require("../assets/flashcards/flashcardbg.png")}
style={{ width: ITEM_WIDTH * 0.89, height: ITEM_HEIGHT }} //.89
>
<Image source={item.icon} style={styles.itemImage} />
<Text style={styles.itemLabel}>{`${item.title}`}</Text>
</ImageBackground>
</View>
</Pressable>
</View>
);
}
render() {
return (
<View style={[styles.fullview]}>
<Carousel
ref={(c) => (this.carousel = c)}
data={DATA}
renderItem={this._renderItem}
sliderWidth={SLIDER_WIDTH}
itemWidth={ITEM_WIDTH}
containerCustomStyle={styles.carouselContainer}
inactiveSlideShift={0}
onSnapToItem={(index) => this.setState({ index })}
scrollInterpolator={scrollInterpolator}
slideInterpolatedStyle={animatedStyles}
useScrollView={true}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
// flex: 1,
},
fullview: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#CDE7E1",
},
carouselContainer: {
marginTop: SLIDER_HEIGHT * 0.06,
// marginBottom: SLIDER_HEIGHT * 0.06,
},
itemContainer: {
justifyContent: "center",
width: ITEM_WIDTH,
height: ITEM_HEIGHT,
// display: "flex",
},
itemFlashcard: {
// display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100%",
width: "100%",
textAlign: "center",
},
itemImage: {
marginTop: "35%",
width: "100%",
height: "50%",
justifyContent: "center",
alignItems: "center",
resizeMode: "contain",
},
itemLabel: {
marginTop: "18%",
textAlign: "center",
color: "black",
fontSize: 50,
fontWeight: "500",
},
counter: {
marginTop: 25,
fontSize: 30,
fontWeight: "bold",
textAlign: "center",
},
});
i am facing a problem regarding async storage in react native .
when i setItem in async storage and then retrieve it if there are 3 tasks- which i have added,
only two of them is retrieved
i will share a photo of before and after
this is output before refreshing
this is the output after refreshing the app
This is my app.js code
import { StatusBar } from 'expo-status-bar';
import {
StyleSheet,
Text,
View,
KeyboardAvoidingView,
FlatList,
TextInput,
TouchableOpacity,
Keyboard,
} from 'react-native';
import React, { Component } from 'react';
import * as Font from 'expo-font';
import Task from './components/Task';
import AppLoading from 'expo-app-loading';
import AsyncStorage from '#react-native-async-storage/async-storage';
let customFonts = {
Poppins_SemiBold: require('./assets/Poppins-SemiBold.ttf'),
Poppins_Regular: require('./assets/Poppins-Regular.ttf'),
};
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
task: '',
taskItems: [],
fontsLoaded: false,
};
}
async _loadFontsAsync() {
await Font.loadAsync(customFonts);
this.setState({ fontsLoaded: true });
}
componentDidMount() {
this._loadFontsAsync();
this._retrieveData()
}
_retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('data');
if (value.length !== 2) {
// We have data!!
this.setState({taskItems:[...JSON.parse(value)]})
console.log(value);
}
} catch (error) {
// Error retrieving data
console.log(error)
}
};
handleAddTask=()=>{
Keyboard.dismiss()
this.setState({taskItems:[...this.state.taskItems,this.state.task]})
this.setState({task:''})
AsyncStorage.setItem('data',JSON.stringify(this.state.taskItems))
}
deleteItem=(index)=>{
try {
let arr = [...this.state.taskItems];
arr.splice(index, 1);
this.setState({taskItems:arr})
AsyncStorage.setItem('data',JSON.stringify(arr))
} catch (err) {
console.log(err);
}
}
render() {
if (!this.state.fontsLoaded) {
return <AppLoading />;
}
return (
<View style={styles.container}>
{/* Todays Tasks */}
<View style={styles.taskWrapper}>
<Text style={styles.sectionTitle}>Today's Tasks</Text>
<View style={styles.items}>
{/* This is where the tasks will go! */}
<FlatList
data={this.state.taskItems}
keyExtractor={(item) => item}
renderItem={({ item, index }) => (
<Task text={item} handleDelete={() => this.deleteItem(index)} />
)}
/>
</View>
</View>
{/* Write a Task */}
<KeyboardAvoidingView style={styles.writeTaskWrapper}>
<TextInput
style={styles.input}
placeholder={'Write A Task!'}
onChangeText={(text) => {
this.setState({ task: text });
}}
value={this.state.task}
/>
<TouchableOpacity
onPress={() => {
this.handleAddTask();
}}>
<View style={styles.addWrapper}>
<Text style={styles.addText}>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
taskWrapper: {
paddingTop: 80,
paddingHorizontal: 20,
},
sectionTitle: {
fontSize: 24,
backgroundColor: '#fff',
fontFamily: 'Poppins_SemiBold',
borderRadius: 10,
margin: 'auto',
width: 250,
height: 60,
textAlign: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.2,
shadowRadius: 2,
elevation: 5,
paddingTop: 10,
},
items: {
marginTop: 30,
},
writeTaskWrapper: {
position: 'absolute',
bottom: 60,
width: '100%',
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
},
input: {
paddingVertical: 15,
paddingHorizontal: 15,
backgroundColor: '#fff',
borderRadius: 60,
width: 250,
fontFamily: 'Poppins_Regular',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 3,
},
addWrapper: {
width: 60,
height: 60,
backgroundColor: '#fff',
borderRadius: 60,
justifyContent: 'center',
alignItems: 'center',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 3,
},
addText: {},
});
and this is my task.js code which is a component:
import React from 'react';
import {
View,
Text,
StyleSheet,
Dimensions,
Animated,
TouchableOpacity,
} from 'react-native';
import AppLoading from 'expo-app-loading';
import {
Poppins_100Thin,
Poppins_100Thin_Italic,
Poppins_200ExtraLight,
Poppins_200ExtraLight_Italic,
Poppins_300Light,
Poppins_300Light_Italic,
Poppins_400Regular,
Poppins_400Regular_Italic,
Poppins_500Medium,
Poppins_500Medium_Italic,
Poppins_600SemiBold,
Poppins_600SemiBold_Italic,
Poppins_700Bold,
Poppins_700Bold_Italic,
Poppins_800ExtraBold,
Poppins_800ExtraBold_Italic,
Poppins_900Black,
Poppins_900Black_Italic,
} from '#expo-google-fonts/poppins';
import { useFonts } from 'expo-font';
import Swipeable from 'react-native-gesture-handler/Swipeable';
const SCREEN_WIDTH = Dimensions.get('window').width;
const Task = (props) => {
let [fontsLoaded, error] = useFonts({
Poppins_100Thin,
Poppins_100Thin_Italic,
Poppins_200ExtraLight,
Poppins_200ExtraLight_Italic,
Poppins_300Light,
Poppins_300Light_Italic,
Poppins_400Regular,
Poppins_400Regular_Italic,
Poppins_500Medium,
Poppins_500Medium_Italic,
Poppins_600SemiBold,
Poppins_600SemiBold_Italic,
Poppins_700Bold,
Poppins_700Bold_Italic,
Poppins_800ExtraBold,
Poppins_800ExtraBold_Italic,
Poppins_900Black,
Poppins_900Black_Italic,
});
if (!fontsLoaded) {
return <AppLoading />;
}
const leftSwipe = (progress, dragX) => {
const scale = dragX.interpolate({
inputRange: [0, 100],
outputRange: [0, 1],
extrapolate: 'clamp',
});
return (
<TouchableOpacity onPress={props.handleDelete} activeOpacity={0.6}>
<View style={styles.deleteBox}>
<Animated.Text
style={{
transform: [{ scale: scale }],
color: '#fff',
fontFamily: 'Poppins_400Regular',
fontSize: 18,
}}>
Delete
</Animated.Text>
</View>
</TouchableOpacity>
);
};
return (
<Swipeable renderLeftActions={leftSwipe}>
<View style={styles.item}>
<View style={styles.itemLeft}>
<View style={styles.square}></View>
<Text style={styles.itemText}>{props.text}</Text>
</View>
<View style={styles.circular}></View>
</View>
</Swipeable>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: 'white',
padding: 15,
borderRadius: 10,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 3,
},
itemLeft: {
flexDirection: 'row',
alignItems: 'center',
flexWrap: 'wrap',
},
square: {
width: 24,
height: 24,
backgroundColor: '#55BCF6',
opacity: 0.5,
borderRadius: 5,
marginRight: 15,
},
itemText: {
maxWidth: '80%',
fontFamily: 'Poppins_400Regular',
},
circular: {
width: 12,
height: 12,
borderColor: '#55BCF6',
borderWidth: 2,
borderRadius: 5,
},
deleteBox: {
backgroundColor: 'red',
justifyContent: 'center',
alignItems: 'center',
width: 100,
height: 55,
borderRadius: 10,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.5,
shadowRadius: 2,
elevation: 5,
},
});
export default Task;
Due to React internal state update implementation, update Async storage run before new state updated. It's recommended to run asynchronous code before updating the state.
To solve the issue, refactor your code as below:
handleAddTask= async ()=>{
Keyboard.dismiss()
const updatedTaskItems = [...this.state.taskItems,this.state.task]
await AsyncStorage.setItem('data',JSON.stringify(updatedTaskItem))
this.setState({taskItems:updatedTaskUtems,task:''})
}
I have created this code but it isn't working, I have created four input fields for pin code when users press the numeric it should move to the input field and turn that fields in the mask, like in * part so I am trying to add that one but something I am missing also I am not getting the four digits pin code when console the function please help me out.
import React, { Component, useLayoutEffect, useState } from "react";
import {
StyleSheet,
Text,
View,
ImageBackground,
SafeAreaView,
Image,
TouchableOpacity,
TouchableOpacityBase,
TextInput,
} from "react-native";
import Theme from "../../utils/Theme";
import OTPInputView from "#twotalltotems/react-native-otp-input";
const hRem = AppStore.screenHeight / 812;
const wRem = AppStore.screenWidth / 375;
class PinAuthentication extends Component {
constructor(props) {
super(props);
this.state = {
passcode: ["", "", "", ""],
};
}
onPressNumber = (num) => {
const tempcode = this.state.passcode;
for (let i = 0; i < tempcode.length; i++) {
if (tempcode[i] == "") {
tempcode[i] = num;
break;
} else {
continue;
}
}
this.setState({ passcode: tempcode });
};
onPressCancel = (num) => {
const tempcode = this.state.passcode;
for (let i = tempcode.length; i >= 0; i--) {
if (tempcode[i] != "") {
tempcode[i] = "";
break;
} else {
continue;
}
}
this.setState({ passcode: tempcode });
};
render() {
let numbers = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 6 },
{ id: 7 },
{ id: 8 },
{ id: 9 },
{
id: 10,
},
{ id: 0 },
{
id: 11,
},
];
return (
<>
<ImageBackground
style={styles.container}
source={require("../../assets/Images/SliderImages/Background02sc.png")}
/>
<View style={styles.headerStyle}>
<TouchableOpacity>
<Image
style={styles.backButton}
source={require("../../assets/Images/SliderImages/Icon/BackButton.png")}
/>
</TouchableOpacity>
<View>
<Text style={styles.pinText}>Set new PIN</Text>
</View>
</View>
<View></View>
<View></View>
<View>
<Text style={styles.pinConfirmationText}>Enter new PIN</Text>
</View>
{/* <View style={{ alignItems: "center" }}>
<OTPInputView
style={{ width: "80%", height: 200 }}
pinCount={4}
// code={this.state.code} //You can supply this prop or not. The component will be used as a controlled / uncontrolled component respectively.
// onCodeChanged = {code => { this.setState({code})}}
autoFocusOnLoad
codeInputFieldStyle={styles.underlineStyleBase}
codeInputHighlightStyle={styles.underlineStyleHighLighted}
onCodeFilled={(code) => {
console.log(`Code is ${code}, you are good to go!`);
}}
secureTextEntry={true}
// keyboardType={false}
/>
</View> */}
<View style={styles.codeContainer}>
{this.state.passcode.map((x) => {
let codes = x != "" ? styles.inputBox1 : styles.inputBox;
return (
<View style={codes}>{/* <Text style={codes}></Text> */}</View>
);
})}
</View>
<View style={{ alignItems: "center", justifyContent: "center" }}>
<View style={styles.numberContainer}>
{numbers.map((num, numb) => {
return (
<>
{num.id == 10 ? (
<TouchableOpacity
key={num.id}
onPress={() => this.onPressCancel()}
style={styles.number}
>
<Image
style={styles.img}
source={require("../../assets/Images/SliderImages/Icon/icons_cancel_last_digit.png")}
/>
</TouchableOpacity>
) : num.id == 11 ? (
<TouchableOpacity
key={num.id}
onPress={() => this.onPressCancel()}
style={styles.number}
>
<Image
style={styles.img}
source={require("../../assets/Images/SliderImages/Icon/icons_check.png")}
/>
</TouchableOpacity>
) : (
<TouchableOpacity
key={num.id}
onPress={() => this.onPressNumber(num.id)}
style={styles.number}
>
<Text style={styles.numberText}>{num.id}</Text>
</TouchableOpacity>
)}
</>
);
})}
</View>
</View>
</>
);
}
}
export default PinAuthentication;
const styles = StyleSheet.create({
container: {
flex: 1,
position: "absolute",
top: 0,
right: 0,
left: 0,
bottom: 0,
backgroundColor: "#021831",
},
headerStyle: {
flexDirection: "row",
marginTop: hRem * 56,
marginHorizontal: wRem * 24,
alignItems: "center",
},
backButton: {
width: wRem * 12,
height: hRem * 21,
},
pinText: {
color: "white",
textAlign: "center",
alignSelf: "center",
marginLeft: wRem * 101,
fontSize: hRem * 18,
...Theme.encodeSansMed1,
lineHeight: hRem * 16,
},
pinConfirmationText: {
textAlign: "center",
marginTop: hRem * 44,
color: "white",
...Theme.encodeSansMed3,
lineHeight: hRem * 19.07,
},
borderStyleBase: {
width: 30,
height: 45,
},
borderStyleHighLighted: {
borderColor: "#707070",
},
underlineStyleBase: {
width: wRem * 62,
height: 45,
borderWidth: 0,
borderBottomWidth: 1,
},
underlineStyleHighLighted: {
borderColor: "#FFFFFF",
},
number: {
width: wRem * 77,
height: hRem * 77,
borderRadius: wRem * 77,
backgroundColor: "#000000",
justifyContent: "center",
alignItems: "center",
marginHorizontal: wRem * 12,
marginVertical: hRem * 9,
},
numberContainer: {
flexDirection: "row",
flexWrap: "wrap",
marginTop: hRem * 95,
alignItems: "center",
justifyContent: "center",
shadowColor: Theme.shadow_Button,
shadowOffset: {
width: 1,
height: 1,
},
shadowOpacity: 1.5,
shadowRadius: 5,
elevation: 3,
},
numberText: {
...Theme.encodeSansMed4,
// lineHeight: hRem * 16,
position: "absolute",
textAlign: "center",
color: Theme.white_color,
},
codeContainer: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
marginHorizontal: wRem * 49,
marginTop: hRem * 50,
},
code: {
width: wRem * 62,
height: hRem * 2,
borderColor: "#FFFFFF",
borderWidth: 1,
borderRadius: 13,
},
inputBox: {
width: wRem * 62,
borderBottomWidth: 1,
borderWidth: 1,
// height: 13,
// width: 13,
borderColor: "#FFFFFF",
// alignItems: "center",
// justifyContent: "space-between",
// backgroundColor: "white",
// borderRadius: 13,
},
inputBox1: {
width: wRem * 62,
borderBottomWidth: 1,
borderWidth: 1,
// height: 13,
// width: 13,
borderColor: "#FFFFFF",
// alignItems: "center",
// justifyContent: "space-between",
// backgroundColor: "white",
// borderRadius: 13,
},
inputText: {
color: "white",
...Theme.encodeSansMed3,
paddingBottom: hRem * 21,
backgroundColor: "green",
width: 20,
},
inputText1: {
color: "white",
...Theme.encodeSansMed3,
paddingBottom: hRem * 21,
},
img: {
width: wRem * 30,
height: hRem * 22,
},
});
I have created this code but it isn't working, I have created four input fields for pin code when users press the numeric it should move to the input field and turn that fields in the mask, like in * part so I am trying to add that one but something I am missing also I am not getting the four digits pin code when console the function
I have been trying to build a a media player in react native using Expo to be able to play audio on my music project.
I have successfully hacked one together with the preferred design but I still have a big limitation. I will love to implement a progress bar that will show how far the song has played.
Here is my player design. Secondly, How do I substitute this progress bar for IOS ??
render() {
return (
<View >
<View style={styles.container} >
<Image
style={styles.imageStyle}
source={{uri: this.state.coverName || this.MusicPlayer.getCurrentItemCover()}}
/>
<View >
<Text style = {styles.artistName}> {this.state.artistName || this.MusicPlayer.getCurrentItemArtistName()}</Text>
</View>
<View style={{paddingRight:2, paddingLeft:2}}>
<Text style={styles.songStyle}> {this.state.title || this.MusicPlayer.getCurrentSongTitle()}</Text>
</View>
<ProgressBarAndroid style={{marginLeft:10, marginRight:10}} styleAttr="Horizontal" color="#2196F3" indeterminate={false} progress={0.5} />
<View style={{flexDirection:'row', padding:10, alignItems:'center', justifyContent:'center'}}>
<Text style={styles.iconStyle2} onPress={this.playPrev}>
<Feather name="rewind" size={20} style={styles.text} />
</Text>
{this.state.playing?
<Text style={styles.iconStyle2} onPress={this.startStopPlay}>
<Feather name="pause" size={24} style={styles.text} />
</Text>
:
<Text style={styles.iconStyle2} onPress={this.startStopPlay}>
<Feather name="play-circle" size={24} style={styles.text} />
</Text>
}
<Text style={styles.iconStyle2} onPress={this.playNext}>
<Feather name="fast-forward" size={20} style={styles.text} />
</Text>
</View>
</View>
</View>
);
}
}
My Play Function
startPlay = async (index = this.index, playing = false) => {
const url = this.list[index].url;
this.index = index;
console.log(url);
// Checking if now playing music, if yes stop that
if(playing) {
await this.soundObject.stopAsync();
} else {
// Checking if item already loaded, if yes just play, else load music before play
if(this.soundObject._loaded) {
await this.soundObject.playAsync();
} else {
await this.soundObject.loadAsync(url);
await this.soundObject.playAsync();
}
}
};
My main goal is to get a small player on mobile close to this.
I am working with React native Expo version.
FullCode Of Music Player Android AND ios Both in working
SeekBar.js
import React, { Component } from 'react';
import { defaultString } from '../String/defaultStringValue';
import {
View,
Text,
StyleSheet,
Image,
Slider,
TouchableOpacity,
} from 'react-native';
function pad(n, width, z = 0) {
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
const minutesAndSeconds = (position) => ([
pad(Math.floor(position / 60), 2),
pad(position % 60, 2),
]);
const SeekBar = ({
trackLength,
currentPosition,
onSeek,
onSlidingStart,
}) => {
const elapsed = minutesAndSeconds(currentPosition);
const remaining = minutesAndSeconds(trackLength - currentPosition);
return (
<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
<Text style={[styles.text, { color: defaultString.darkColor }]}>
{elapsed[0] + ":" + elapsed[1]}
</Text>
<View style={{ flex: 1 }} />
<Text style={[styles.text, { width: 40, color: defaultString.darkColor }]}>
{trackLength > 1 && "-" + remaining[0] + ":" + remaining[1]}
</Text>
</View>
<Slider
maximumValue={Math.max(trackLength, 1, currentPosition + 1)}
onSlidingStart={onSlidingStart}
onSlidingComplete={onSeek}
value={currentPosition}
minimumTrackTintColor={defaultString.darkColor}
maximumTrackTintColor={defaultString.lightGrayColor}
thumbStyle={styles.thumb}
trackStyle={styles.track}
/>
</View>
);
};
export default SeekBar;
const styles = StyleSheet.create({
slider: {
marginTop: -12,
},
container: {
paddingLeft: 16,
paddingRight: 16,
paddingTop: 16,
},
track: {
height: 2,
borderRadius: 1,
},
thumb: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: defaultString.darkColor,
},
text: {
color: 'rgba(255, 255, 255, 0.72)',
fontSize: 12,
textAlign: 'center',
}
});
Player.js
import React, { Component } from 'react';
import {
View,
Text,
StatusBar,
} from 'react-native';
import Header from './Header';
import AlbumArt from './AlbumArt';
import TrackDetails from './TrackDetails';
import SeekBar from './SeekBar';
import Controls from './Controls';
import Video from 'react-native-video';
export default class Player extends Component {
constructor(props) {
super(props);
this.state = {
paused: true,
totalLength: 1,
currentPosition: 0,
selectedTrack: 0,
repeatOn: false,
shuffleOn: false,
};
}
setDuration(data) {
this.setState({ totalLength: Math.floor(data.duration) });
}
setTime(data) {
this.setState({ currentPosition: Math.floor(data.currentTime) });
}
seek(time) {
time = Math.round(time);
this.refs.audioElement && this.refs.audioElement.seek(time);
this.setState({
currentPosition: time,
paused: false,
});
}
onBack() {
if (this.state.currentPosition < 10 && this.state.selectedTrack > 0) {
this.refs.audioElement && this.refs.audioElement.seek(0);
this.setState({ isChanging: true });
setTimeout(() => this.setState({
currentPosition: 0,
paused: false,
totalLength: 1,
isChanging: false,
selectedTrack: this.state.selectedTrack - 1,
}), 0);
} else {
this.refs.audioElement.seek(0);
this.setState({
currentPosition: 0,
});
}
}
onForward() {
if (this.state.selectedTrack < this.props.tracks.length - 1) {
this.refs.audioElement && this.refs.audioElement.seek(0);
this.setState({ isChanging: true });
setTimeout(() => this.setState({
currentPosition: 0,
totalLength: 1,
paused: false,
isChanging: false,
selectedTrack: this.state.selectedTrack + 1,
}), 0);
}
}
render() {
const track = this.props.tracks[this.state.selectedTrack];
const video = this.state.isChanging ? null : (
<Video source={{ uri: track.audioUrl }} // Can be a URL or a local file.
ref="audioElement"
playInBackground={true}
playWhenInactive={true}
paused={this.state.paused} // Pauses playback entirely.
resizeMode="cover" // Fill the whole screen at aspect ratio.
repeat={true} // Repeat forever.
onLoadStart={this.loadStart} // Callback when video starts to load
onLoad={this.setDuration.bind(this)} // Callback when video loads
onProgress={this.setTime.bind(this)} // Callback every ~250ms with currentTime
onEnd={this.onEnd} // Callback when playback finishes
onError={this.videoError} // Callback when video cannot be loaded
style={styles.audioElement} />
);
return (
<View style={styles.container}>
{/* <StatusBar hidden={true} /> */}
{/* <Header message="Playing From Charts" /> */}
<AlbumArt url={track.albumArtUrl} />
<TrackDetails title={track.title} artist={track.artist} />
<SeekBar
onSeek={this.seek.bind(this)}
trackLength={this.state.totalLength}
onSlidingStart={() => this.setState({ paused: true })}
currentPosition={this.state.currentPosition}
/>
<Controls
onPressRepeat={() => this.setState({ repeatOn: !this.state.repeatOn })}
repeatOn={this.state.repeatOn}
shuffleOn={this.state.shuffleOn}
forwardDisabled={this.state.selectedTrack === this.props.tracks.length - 1}
onPressShuffle={() => this.setState({ shuffleOn: !this.state.shuffleOn })}
onPressPlay={() => this.setState({ paused: false })}
onPressPause={() => this.setState({ paused: true })}
onBack={this.onBack.bind(this)}
onForward={this.onForward.bind(this)}
paused={this.state.paused} />
{video}
</View>
);
}
}
const styles = {
container: {
flex: 1,
backgroundColor: '#ffffff',
},
audioElement: {
height: 0,
width: 0,
}
};
AlbumArt.js
import React, { Component } from 'react';
import {
View,
Text,
StyleSheet,
Image,
TouchableHighlight,
TouchableOpacity,
Dimensions,
} from 'react-native';
const AlbumArt = ({
url,
onPress
}) => (
<View style={styles.container}>
<TouchableOpacity onPress={onPress}>
<View
style={[styles.image, {
elevation: 10, shadowColor: '#d9d9d9',
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 1,
shadowRadius: 2,
borderRadius: 20,
backgroundColor: '#ffffff'
}]}
>
<Image
style={[styles.image, { borderRadius: 20 }]}
source={{ uri: url }}
/>
</View>
</TouchableOpacity>
</View>
);
export default AlbumArt;
const { width, height } = Dimensions.get('window');
const imageSize = width - 100;
const styles = StyleSheet.create({
container: {
alignItems: 'center',
marginTop: 30,
paddingLeft: 24,
paddingRight: 24,
},
image: {
width: imageSize,
height: imageSize,
},
})
App.js
import React, { Component } from 'react';
import Player from './Player';
import { BackHandler } from 'react-native';
import i18n from '../../Assets/I18n/i18n';
import { Actions } from 'react-native-router-flux';
export default class MusicPlayer extends Component {
constructor(props) {
super(props);
const { navigation } = this.props;
this.state = {
song: navigation.getParam('songid')
};
this.props.navigation.setParams({
title: i18n.t('Panchkhan')
})
}
componentWillMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton = () => {
Actions.pop();
return true;
};
render() {
const TRACKS = [
{
title: 'Stressed Out',
artist: 'Twenty One Pilots',
albumArtUrl: "https://cdn-images-1.medium.com/max/1344/1*fF0VVD5cCRam10rYvDeTOw.jpeg",
audioUrl: this.state.song
}
];
return <Player tracks={TRACKS} />
}
}
Controls.js
import React, { Component } from 'react';
import { defaultString } from '../String/defaultStringValue';
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity,
} from 'react-native';
const Controls = ({
paused,
shuffleOn,
repeatOn,
onPressPlay,
onPressPause,
onBack,
onForward,
onPressShuffle,
onPressRepeat,
forwardDisabled,
}) => (
<View style={styles.container}>
<TouchableOpacity activeOpacity={0.0} onPress={onPressShuffle}>
<Image style={[{ tintColor: defaultString.darkColor } , styles.secondaryControl, shuffleOn ? [] : styles.off]}
source={require('../img/ic_shuffle_white.png')} />
</TouchableOpacity>
<View style={{ width: 40 }} />
<TouchableOpacity onPress={onBack}>
<Image style={{ tintColor: defaultString.darkColor }} source={require('../img/ic_skip_previous_white_36pt.png')} />
</TouchableOpacity>
<View style={{ width: 20 }} />
{!paused ?
<TouchableOpacity onPress={onPressPause}>
<View style={styles.playButton}>
<Image style={{ tintColor: defaultString.darkColor }} source={require('../img/ic_pause_white_48pt.png')} />
</View>
</TouchableOpacity> :
<TouchableOpacity onPress={onPressPlay}>
<View style={styles.playButton}>
<Image style={{ tintColor: defaultString.darkColor }} source={require('../img/ic_play_arrow_white_48pt.png')} />
</View>
</TouchableOpacity>
}
<View style={{ width: 20 }} />
<TouchableOpacity onPress={onForward}
disabled={forwardDisabled}>
<Image style={[forwardDisabled && { opacity: 0.3 }, { tintColor: defaultString.darkColor }]}
source={require('../img/ic_skip_next_white_36pt.png')} />
</TouchableOpacity>
<View style={{ width: 40 }} />
<TouchableOpacity activeOpacity={0.0} onPress={onPressRepeat}>
<Image style={[{ tintColor: defaultString.darkColor }, styles.secondaryControl, repeatOn ? [] : styles.off]}
source={require('../img/ic_repeat_white.png')} />
</TouchableOpacity>
</View>
);
export default Controls;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingTop: 8,
},
playButton: {
height: 72,
width: 72,
borderWidth: 1,
borderColor: defaultString.darkColor,
borderRadius: 72 / 2,
alignItems: 'center',
justifyContent: 'center',
},
secondaryControl: {
height: 18,
width: 18,
},
off: {
opacity: 0.30,
}
})
controlDetails.js
import React, { Component } from 'react';
import { defaultString } from '../String/defaultStringValue';
import {
View,
Text,
StyleSheet,
Image,
TouchableHighlight,
TouchableOpacity,
Dimensions,
} from 'react-native';
const TrackDetails = ({
title,
artist,
onAddPress,
onMorePress,
onTitlePress,
onArtistPress,
}) => (
<View style={styles.container}>
{/* <TouchableOpacity onPress={onAddPress}>
<Image style={styles.button}
source={require('../img/ic_add_circle_outline_white.png')} />
</TouchableOpacity> */}
<View style={styles.detailsWrapper}>
<Text style={styles.title} onPress={onTitlePress}>{title}</Text>
<Text style={styles.artist} onPress={onArtistPress}>{artist}</Text>
</View>
{/* <TouchableOpacity onPress={onMorePress}>
<View style={styles.moreButton}>
<Image style={styles.moreButtonIcon}
source={require('../img/ic_more_horiz_white.png')} />
</View>
</TouchableOpacity> */}
</View>
);
export default TrackDetails;
const styles = StyleSheet.create({
container: {
paddingTop: 24,
flexDirection: 'row',
paddingLeft: 20,
alignItems: 'center',
paddingRight: 20,
},
detailsWrapper: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
},
title: {
fontSize: 16,
fontWeight: 'bold',
color: defaultString.darkColor,
textAlign: 'center',
},
artist: {
color: defaultString.darkColor,
fontSize: 12,
marginTop: 4,
},
button: {
opacity: 0.72,
},
moreButton: {
borderColor: 'rgb(255, 255, 255)',
borderWidth: 2,
opacity: 0.72,
borderRadius: 10,
width: 20,
height: 20,
alignItems: 'center',
justifyContent: 'center',
},
moreButtonIcon: {
height: 17,
width: 17,
}
});