In nested stack navigation in react-navigation. it does not to scroll up - react-navigation

I have a problem.
I had coded react-native and react-navigation.
In 'HOME' screen, I had scrolled down, and When I had pressed the icon 'HOME',
There are no any changes to scroll.
Certainly, I have used 'ref - useScrollToTop method', But I cannot go to screen up
<Tab.Navigator>
<Tab.screen name='home' component={HomeNavigation} options={{ <Image ...(blah blah) /> }} />
</Tab.Navigator>
----
<HomeNavigation.Navigator initialRouteName="Main" name="Main" component={HomeTopTabNavigation}>
<HomeNavigation.Screen name="Main" component={HomeTopTabNavigation} />
<HomeNavigation.Navigator />
----
<HomeTopTabNavigation.Navigator initialRouteName='NEW'>
<HomeTopTabNavigation.Screen name="NEW" component={Home} />
<HomeTopTabNavigation.Screen name="HOT" component={HOT} />
</HomeTopTabNavigation.Navigator>
----
const Home = ({ navigation }) => {
const ref = React.useRef(null); *******. This ref does not work !
useScrollToTop(ref); *******. This ref does not work !
...
return (
...
<FlatList
ref ={ref} *******. This ref does not work !
...
/>
)
}
more specific navigation name in this picture. please see this.

Related

React-native Why Menu is not rendering

i have a menu for each item of a flatlist, however when ever i press on the button to show the menu nothing happens when i log the visible state of the menu i see that it is being set to true but it is not rendering.
this is a component to render each item with a menu
const RenderItem =(props)=>{
return(
<TouchableOpacity onPress={()=>{}}>
<View style={styles.flatitem}>
<Icon style={styles.pdf} name="file-pdf-o" color="#666"/>
<Text style={styles.itemtext}>{props.title}</Text>
<Menu
visible={visible}
{...console.log(visible)}
anchor={<Button onPress={openMenu} >
show
</Button>}
onDismiss={closeMenu} >
<Menu.Item icon="pencil-box-outline" onPress={() =>{}} title="Rename" />
<Menu.Item icon="label-outline" onPress={() => {}} title="Label" />
<Menu.Item icon="delete-outline" onPress={() => {}} title="Delete" />
</Menu>
</View>
</TouchableOpacity> )}
this is the flatlist:
<FlatList style={styles.flatstyle}
keyExtractor={(item)=>item['id']}
data={DATA}
renderItem={({item})=>(<RenderItem title={item.title }/>)}
/>
and these are the open and close functions
const [visible,setVisible]=useState(false)
const openMenu = () => {
setVisible(true)
}
const closeMenu = () => setVisible(false);
If i am right, it is actually not a problem. FlatList is a pure component and will only re-render if the data prop changes i.e, the data passed to the flatlist changes.
As visible is not in data, so it doesnot re-render.
To make it re-render and show the menu, you need to use extraData prop of the flatlist, which will take some other data. If that other data changes, that will also cause a re-render and that other data in your case is the visible variable.
More details here

set header for drawer navigation

I tried to set header in react navigation v5 by setting options without any change
<Drawer.Navigator
initialRouteName='...'
>
<Drawer.Screen
name='...'
component={Component}
options={{ title: 'My home' }}
/>
</Drawer.Navigator>
is there a way I could have my react navigation header in drawer?
Update: The latest version of drawer navigator now has a header (can be shown with headerShown: true)
Drawer Navigator doesn't provide a header.
If you want to show headers in drawer screens, you have 2 options:
Provide your own header component. You can use header from libraries such as react-native-paper
Nest a Stack Navigator in each drawer screen where you want to show a header.
I was looking for the solution, however did not find any nice way to wrap up every component automatically with custom header. So I ended up creating HOC component and wrapping each component for every screen.
import React, {Fragment} from 'react';
const NavHeader = props => {
// ... NavHeader code goes here
};
export const withHeader = Component => {
return props => {
return (
<Fragment>
<NavHeader {...props} />
<Component {...props} />
</Fragment>
);
};
};
Then in your Drawer you do:
<Drawer.Navigator>
<Drawer.Screen
name={ROUTES.DASHBOARD}
component={withHeader(DashboardContainer)} // <--- Wrap it around component here.
/>
</Drawer.Navigator>
This is a simple example with react navigation 5:
function Root() {
return (
<Stack.Navigator>
<Stack.Screen name="Profile" component={Profile} />
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
);
}
function App() {
return (
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Home} />
<Drawer.Screen name="Root" component={Root} />
</Drawer.Navigator>
</NavigationContainer>
);
}
You can find about the navigation to a screen in a nested navigator in docs and you can try this example on Snack

react-native iOS Photos features

I am new to React-Native. With help from this forum and others, I was able to create a small App with images loading from Firebase in ListView. I have a question ... is it possible to implement features that are in iOS Photos?
What I am trying to do is, when a user touches and holds on an image in ListView, I would like to popup the image with options (Like, Favorite) in the image below. Appreciate any help.
Update:
I changed the code like this:
render() {
return (
<View style={styles.container}>
<ListView dataSource={this.state.dataSource} renderRow={this._renderItem.bind(this)} enableEmptySections={true} removeClippedSubviews={true} style={styles.listview}> </ListView>
</View>
);
}
_renderItem(item) {
return (
<ListItem item={item}/>
);
}
ListItem.js
class ListImages extends Component {
render() {
return (
<MenuContext style={{flexDirection: 'row', padding: 5}}>
<Menu onSelect={value => alert(`Selected number: ${value}`)}>
<MenuTrigger>
<Image resizeMode={Image.resizeMode.contain} style={{width: 400, height: 250}} source={{ uri: this.props.item.name }} />
</MenuTrigger>
<MenuOptions>
<View width={400} height={600} style={styles.listimagecontainer}>
<Image resizeMode={Image.resizeMode.contain} style={{width: 350, height: 500}} source={{ uri: this.props.item.name }} />
</View>
<MenuOption value={1} text='Test' />
</MenuOptions>
</Menu>
</MenuContext>
);
}
}
Images in the ListView are displaying ok. When I click on any image, new view opens up with the image. But the next image in the ListView overlays on the view hiding more than half the view. What am I doing wrong here ? I also want to display the image in full with correct aspect ratio. Appreciate any help.
UPDATE with suggested code:
<MenuContext style={{flexDirection: 'row', padding: 5}}>
<Menu onSelect={value => alert(`Selected number: ${value}`)}>
<MenuTrigger>
<Image resizeMode={Image.resizeMode.contain} style={{width: 400, height: 250}} source={{ uri: this.props.item.name }} />
</MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => alert(`Like`)} text='Like' />
<MenuOption onSelect={() => alert(`Share`)} text='Share' />
<MenuOption onSelect={() => alert(`Delete`)} text='Delete' />
</MenuOptions>
</Menu>
</MenuContext>
Here is screen shot:
What I am trying to do is, ListView displays images at 400x250. When the user clicks on the image, show a larger image of the same (say 325x500 like in iOS) and present the user with options say - like, share, delete. Appreciate any help.
It looks like you have two images, hence why you see two.
MenuTrigger is the component you want the user to click on (in your case it is the image).
MenuOptions is a "list" of the things you want to popup for example three Text: "Like" "Share" "Delete" .. etc.
But it is clear that you have the same image both under trigger and under options. What you want is something like this:
<MenuContext style={{flexDirection: 'row', padding: 5}}>
<Menu onSelect={value => alert(`Selected number: ${value}`)}>
<MenuTrigger>
<Image resizeMode={Image.resizeMode.contain} style={{width: 400, height: 250}} source={{ uri: this.props.item.name }} />
</MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => alert(`Like`)} text='Like' />
<MenuOption onSelect={() => alert(`Share`)} text='Share' />
<MenuOption onSelect={() => alert(`Delete`)} text='Delete' />
</MenuOptions>
</Menu>
</MenuContext>

Nativescript ActionBar custom component

I am trying to create a custom component as described here in order to reuse the action bar and its logic in different places of my app.
Here is what I have setup the component:
/components/header/header.xml
<ActionBar title="Title" class="{{ 'mode' == dark ? 'bg-dark' : 'bg-white' }}" loaded="loaded">
</ActionBar>
/components/header/header.ts
exports.loaded = (args) => {
let page = <Page> args.object;
let pageObservable = new Observable({
'mode' : page.get('mode')
});
page.bindingContext = pageObservable;
}
I then try to use the component calling it like this :
some_view.xml
<Page
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:header="components/header">
<header:header mode="dark"/>
<StackLayout>..</StackLayout>
...
</Page>
However, navigating to `some-view.xml' I get the following error:
Calling js method onCreateView failed
TypeError: Cannot read property frame of 'undefined'
File "data...../ui/action-bar/action-bar.js" line: 146
Am I doing something wrong?
Have you succeded in creating a custom component based on ActionBar?
Perhaps the problem is that you are trying to get Page instance in the loaded method in your /components/header/header.ts file. args will return you reference to the ActionBar instead of Page. On other hand while using TypeScript the events should be defined like this export function loaded(args){...}. In the above-given code you are using JavaScript syntax. I am attaching sample code, where has been shown, how to create custom component.
component/action-bar/action-bar.xml
<ActionBar loaded="actionbarLoaded" title="Title" icon="">
<NavigationButton text="Back" icon="" tap="" />
<ActionBar.actionItems>
<ActionItem icon="" text="Left" tap="" ios.position="left" />
<ActionItem icon="" text="Right" tap="" ios.position="right" />
</ActionBar.actionItems>
</ActionBar>
component/action-bar/action-bar.ts
export function actionbarLoaded(args){
console.log("actionbar loaded");
}
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" xmlns:AB="component/action-bar">
<Page.actionBar>
<AB:action-bar />
</Page.actionBar>
<StackLayout>
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
</StackLayout>
</Page>
main-page.ts
import { EventData } from 'data/observable';
import { Page } from 'ui/page';
import { HelloWorldModel } from './main-view-model';
// Event handler for Page "navigatingTo" event attached in main-page.xml
export function navigatingTo(args: EventData) {
// Get the event sender
let page = <Page>args.object;
page.bindingContext = new HelloWorldModel();
}

Appcelerator Titanium View Proxy Memory Management

I've been struggling on how to handle memory allocations on my Titanium app (built for android [9.4MB], ios[2.8MB] and MobileWeb[5.4MB].
I have created a widget which will be use to open views from a menu selection.
<Alloy>
<Window id="mainWindow">
<View id="menuView">
<View id="vTop">
<!-- Header goes here -->
<TableView id="menuTable" />
</View>
<!-- footer message goes here -->
</View>
<View id="contentView">
<View id="nav">
<Label id="winTitle"/>
<View id='leftButtonView'>
<Label id="icoLeftButton" />
</View>
<View id='backButtonTitleView'>
<Label id="icoBack" />
<Label id="backButtonTitle" />
</View>
<View id='rightButtonView'>
<Label id="icoRightButton" />
</View>
</View>
<View id="mainView" layout="composite" />
</View>
</Window>
</Alloy>
Sample usage of this widget:
I was able to reduce the memory allocations of views by following this solution. I've applied this every time I open another view from menu selection.
(controller of my widget)
var memPool = Ti.UI.createWindow();
memPool.open();
memPool.hide();
memPool.close();
// Open view from menu selection
function openView(e) {
var cbAdd = function() {
var ctrl = Alloy.createController(e["url"]);
if (ctrl != null) {
setWindowTitle(e["wTitle"]);
setRightIco(ctrl.getRightIco()); //setting right label icon (IcoMoon font)
$.setRightNavClick(ctrl.getRightNavCb());
//Have to passed navGroup to be able to open other views
ctrl.winMain.navGroup = $;
//Close splash screen after layout
ctrl.winMain.addEventListener("postlayout", postLayout);
$.mainView.add(ctrl.winMain);
ctrl.init();
ctrl = null;
}
};
var cbRemove = function() {
//Remove all children from mainView; fn [commonjs]
fn.removeChildren($.mainView, cbAdd);
};
if ($.mainView.children.length > 0) {
cleanUp($.mainView.children[0]);
cbRemove();
} else
cbAdd();
}
function cleanUp(obj, cb) {
memPool.open();
memPool.hide();
memPool.setZIndex(-1);
memPool.add(obj);
memPool.close();
obj = null;
if (cb != null) cb();
}
Checking the result on XCode Instruments:
TiUIView is always reduced everytime I open other views from menu but TiUIViewProxy doesn't.
Sample View to be open: (consist of widgets)
<Alloy>
<View id="winMain">
<ScrollView id="form" layout="vertical">
<Widget id="fperiod" src="ph.com.test.controls.period" top="10" />
<Widget id="ftermid" src="ph.com.test.controls.key" label="Terminal No." top="20" />
<Widget id="fofficeid" src="ph.com.test.controls.combobox" label="Branch" />
<View id="btnReset" width="100%" height="50" layout="horizontal" top="20" bottom="20" backgroundColor="#B40026">
<Label class="resetFilter" />
<Label class="lblReset" />
</View>
</ScrollView>
</View>
</Alloy>
The following are the references that help alot:
http://developer.appcelerator.com/question/116867/this-is-a-solution-to-your-memory-woes#answer-203729
http://www.tidev.io/2014/03/27/memory-management/
http://developer.appcelerator.com/question/152656/tips-and-tricks-for-memory-management
http://developer.appcelerator.com/question/140852/quick-memory-question--tiuiview-vs-tiuiviewproxy
http://developer.appcelerator.com/question/151989/should-i-null-objects-to-release-memory-in-alloy
How to reduce the memory allocations of TiUIViewProxy? Do I have to also cleanup the views of widgets from its controller?
I have tried to cleanup the views of my widgets from its controller. Then, the TiUIViewProxy is somewhat reduced as per checking it on XCode Instruments but my problem is that my app suddenly crashes. I don't know why. Or I'm not just doing it right. Sample clean up function from my widget:
$.cview.remove($.formItemLabel);
$.cview.remove($.lblValue);
$.mView.remove($.cview);
//nulling controller variables goes here
mData = null;
animateLeft = null;
...
This is a really great article on memory management, I follow these guidelines for my own development purposes and highly recommend you read through this.
Memory Management
http://www.tidev.io/2014/03/27/memory-management/

Resources