I'm trying to reproduce the effect seen on first page here: https://github.com/sebawita/starships, where there is a status bar with light content and no action bar.
I have been trying the instructions specified here: https://github.com/NativeScript/nativescript-angular/issues/1779#issuecomment-522586849
I'm working with NativeScript Vue rather than angular, but I don't suppose it matters. Here is my component code:
<template>
<Page
class="page"
ref="page"
statusBarStyle="light"
#loaded="onPageLoaded()">
<GridLayout rows="*, 60, 60, 20, 60, *">
<Label row="0" textWrap="true" class="header" text="Starship Service" />
<TextField
id="emailField"
hint="Email"
keyboardType="email"
returnKeyType="next"
autocorrect="false"
row="1"
class="textfield"
ios.clearButtonMode="1"
ref="field1" />
<TextField
row="2"
secure="true"
hint="Password"
returnKeyType="send"
class="textfield" />
<Button row="4" text="Log in" />
</GridLayout>
</Page>
</template>
<script>
import { topmost } from "tns-core-modules/ui/frame";
import { isIOS } from "tns-core-modules/platform";
export default {
methods: {
onPageLoaded: function(args) {
console.log('page loaded');
if (isIOS) {
Object.defineProperty(UIViewController.prototype, 'preferredStatusBarStyle', {
get: function () {
return this._preferredStatusBarStyle || UIStatusBarStyle.Default;
},
enumerable: true,
configurable: true
});
let controller = topmost().ios.controller;
controller._preferredStatusBarStyle = UIStatusBarStyle.Default;
controller.setNeedsStatusBarAppearanceUpdate();
}
console.log("page loaded done");
},
},
computed: {
message() {
return "Welcome to the first version of the starship app :-)";
}
}
};
</script>
<style scoped lang="scss">
.page {
background-image: url("https://raw.githubusercontent.com/sebawita/starships/master/icons/space-bg.jpg?raw=true");
color: #fff;
}
</style>
I have this in my Info.plist file:
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
You may natively set the status bar style on your page loaded events
HTML
<Page class="page" #loaded="onPageLoaded">
JS
onPageLoaded: function(args) {
let controller = args.object.frame.ios.controller;
controller.navigationBar.barStyle = 0; // `0` for Black or `1` for Light
}
You can also hide the action bar for each component.
import { Page } from 'tns-core-modules/ui/page/page';
constructor(
private page: Page) {
page.actionBarHidden = true;
}
Like was answered in another comment, you need to make sure your Info.plist file has this entry:
<key>UIViewControllerBasedStatusBarAppearance</key>
<true/>
The crucial bit of code needed was added in either NativeScript 6.4 or 6.5 here:
https://github.com/NativeScript/NativeScript/pull/8241/files
This the iOS preferredStatusBarStyle() function on the NativeScript Page object. NativeScript-Vue exposes this as a prop that you can pass in 'light' or 'dark' values to. See the updated Vue documentation.
Related
# i am trying to add image to tab bar item but not able to load in react navigation #
## i am referring https://github.com/react-navigation/react-navigation/issues/1205#issuecomment-296708338 ##
import React from 'react';
import { Text, View, Image } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation'
import ScreenOne from './ScreenOne';
import Screentwo from './Screentwo';
import Preferences from './Preferences';
const TabNavigator = createBottomTabNavigator(
{
Home: {
screen : ScreenOne,
navigationOptions: {
showLabel: false,
tabBarIcon: <Image style={{ width: 30, height: 30 }} source={require('../images/Help_Header_Icon.png'
)}/>,
showIcon: true,
activeTintColor: '#00000',
inactiveTintColor: '#000000'
}
},
Settings: Screentwo,
Preference: Preferences
},
{
initialRouteName: "Home"
}
);
export default createAppContainer(TabNavigator);
### expecting to show image in tab bar item and hide tab bar label###
tabBarIcon
React Element or a function that given { focused: boolean,
horizontal: boolean, tintColor: string } returns a React.Node, to
display in the tab bar. horizontal is true when the device is in
landscape and false when portrait. The icon is re-rendered whenever
the device orientation changes.
Usage
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor, image }) => {
const { routeName } = navigation.state;
let imagepath;
if (routeName === "Home") {
imagepath = require('../images/Help_Header_Icon.png');
} else if (routeName === "Settings") {
imagepath = require('../images/Settings.png');
} else if (routeName === "Preference") {
imagepath = require('../images/Preference.png');
}
return (
<Image
style={{ width: 30, height: 30, resizeMode: "stretch" }}
source={imagepath}
/>
);
Please use Nativebase
https://docs.nativebase.io/Components.html#footer-tabs-icon-headref
import { Container, Header, Content, Footer, FooterTab, Button, Icon } from 'native-base';
<Footer>
<FooterTab>
<Button>
<Icon name="apps" />
</Button>
<Button>
<Icon name="camera" />
</Button>
<Button active>
<Icon active name="navigate" />
</Button>
<Button>
<Icon name="person" />
</Button>
</FooterTab>
</Footer>
I want to make a gender selection using picker. but the mode is not working in ios. Im not sure in android.
<Picker
style={{justifyContent: 'center',backgroundColor: 'white'}}
selectedValue={this.state.gender}
onValueChange={(gender) => this.setState({ gender })}
mode='dialog'
>
<Item label="Male" value="Male" />
<Item label="Female" value="Female" />
</Picker>
Hope anyone could give some suggestion..
Thank you
The <Picker> component renders as a UIPickerView on iOS - that's what you're seeing there. This picker is rendered in-place rather than in a modal (as is the case on Android) - the mode prop you specified only applies to Android.
There are two options: render the picker within something like a <Modal> or use a different component entirely.
I solved this type of issue by doing like this.
import PickerExample from './PickerExample.js';
class Sample extends React.Component {
constructor(props) {
super(props);
this.state = {gender: '',};
this.updateGender = this.updateGender.bind(this);
}
updateGender(val){
this.setState({
gender: val
},function(){
alert("callback function as your wish")
});
}
render(){
return (
<PickerExample gender={this.state.gender} updateGender={this.updateGender.bind(this)} />
);
}
The PickerExample.js file look like this.
export default PickerExample = (props) => {
return (
<Picker selectedValue = {props.gender} onValueChange = {props.updateGender}>
<Picker.Item label = "MALE" value ="Male" />
<Picker.Item label = "Female" value = "female" />
</Picker>
);
}
I use the .ios.jsx extension for the iOS specific picker. Which I code as follows:
export const SelectWidget = ({
selectedOption,
setSelectedOption,
placeholderLabel,
options
}) => {
const items = options.map((option) => {
return <Picker.Item
key={option.key ?? option.label}
label={option.label}
value={option.value}
/>;
});
return (
<Picker
onValueChange={(value) => {
setSelectedOption(value);
}}
placeholder={{
label: placeholderLabel,
value: null,
}}
selectedValue={selectedOption}
style={{
width: '100%', // fill up the width of the device (without this, nothing gets displayed
}}
itemStyle={{
height: 150, // this reduces the height of the selector
color: colors.text, // if you're in dark mode set this to white.
}}
>
// default item
<Picker.Item label={placeholderLabel} value={null} />
{items}
</Picker>
);
};
In iOS safari, OverlayTrigger with trigger="focus" isn't able to dismiss when tapping outside. Here is my code:
<OverlayTrigger
trigger="focus"
placement="right"
overlay={ <Popover id="popoverID" title="Popover Title">
What a popover...
</Popover> } >
<a bsStyle="default" className="btn btn-default btn-circle" role="Button" tabIndex={18}>
<div className="btn-circle-text">?</div>
</a>
</OverlayTrigger>
I know that this is a known bug for Bootstrap cuz this doesn't even work on their own website in iOS, but does anyone know any method to go around it? It would be the best if it is something that doesn't require jQuery, but jQuery solution is welcome. Thanks.
OK, since no one else gives me a work around, I worked on this problem with my co-worker together for 3 days, and we came up with this heavy solution:
THE PROBLEM:
With trigger="focus", Bootstrap Popover/Tooltip can be dismissed when CLICKING outside the Popover/Tooltip, but not TOUCHING. Android browsers apparently changes touches to clicks automatically, so things are fine on Android. But iOS safari and browsers that is based on iOS safari (iOS chrome, iOS firefox, etc...) don't do that.
THE FIX:
We found out that in React Bootstrap, the Overlay component actually lets you customize when to show the Popover/Tooltip, so we built this component InfoOverlay based on Overlay. And to handle clicking outside the component, we need to add event listeners for both the Popover/Tooltip and window to handle both 'mousedown' and 'touchstart'. Also, this method would make the Popover have its smallest width all the time because of the padding-right of the component is initially 0px, and we make based on the width of some parent component so that it is responsive based on the parent component. And the code looks like this:
import React, { Component, PropTypes as PT } from 'react';
import {Popover, Overlay} from 'react-bootstrap';
export default class InfoOverlay extends Component {
static propTypes = {
PopoverId: PT.string,
PopoverTitle: PT.string,
PopoverContent: PT.node,
// You need to add this prop and pass it some numbers
// if you need to customize the arrowOffsetTop, it's sketchy...
arrowOffsetTop: PT.number,
// This is to be able to select the parent component
componentId: PT.string
}
constructor(props) {
super(props);
this.state = {
showPopover: false,
popoverClicked: false
};
}
componentDidMount() {
// Here are the event listeners and an algorithm
// so that clicking popover would not dismiss itself
const popover = document.getElementById('popoverTrigger');
if (popover) {
popover.addEventListener('mousedown', () => {
this.setState({
popoverClicked: true
});
});
popover.addEventListener('touchstart', () => {
this.setState({
popoverClicked: true
});
});
}
window.addEventListener('mousedown', () => {
if (!this.state.popoverClicked) {
this.setState({
showPopover: false
});
} else {
this.setState({
popoverClicked: false
});
}
});
window.addEventListener('touchstart', () => {
if (!this.state.popoverClicked) {
this.setState({
showPopover: false
});
} else {
this.setState({
popoverClicked: false
});
}
});
// this is to resize padding-right when window resizes
window.onresize = ()=>{
this.setState({});
};
}
// This function sets the style and more importantly, padding-right
getStyle() {
if (document.getElementById(this.props.componentId) && document.getElementById('popoverTrigger')) {
const offsetRight = document.getElementById(this.props.componentId).offsetWidth - document.getElementById('popoverTrigger').offsetLeft - 15;
return (
{display: 'inline-block', position: 'absolute', 'paddingRight': offsetRight + 'px'}
);
}
return (
{display: 'inline-block', position: 'absolute'}
);
}
overlayOnClick() {
this.setState({
showPopover: !(this.state.showPopover)
});
}
render() {
const customPopover = (props) => {
return (
{/* The reason why Popover is wrapped by another
invisible Popover is so that we can customize
the arrowOffsetTop, it's sketchy... */}
<div id="customPopover">
<Popover style={{'visibility': 'hidden', 'width': '100%'}}>
<Popover {...props} arrowOffsetTop={props.arrowOffsetTop + 30} id={this.props.PopoverId} title={this.props.PopoverTitle} style={{'marginLeft': '25px', 'marginTop': '-25px', 'visibility': 'visible'}}>
{this.props.PopoverContent}
</Popover>
</Popover>
</div>
);
};
return (
<div id="popoverTrigger" style={this.getStyle()}>
<a bsStyle="default" className="btn btn-default btn-circle" onClick={this.overlayOnClick.bind(this)} role="Button" tabIndex={13}>
<div id="info-button" className="btn-circle-text">?</div>
</a>
<Overlay
show={this.state.showPopover}
placement="right"
onHide={()=>{this.setState({showPopover: false});}}
container={this}>
{customPopover(this.props)}
</Overlay>
</div>
);
}
}
In the end, this is a heavy work around because it is a big amount of code for a fix, and you can probably feel your site is slowed down by a tiny bit because of the 4 event listeners. And the best solution is just tell Bootstrap to fix this problem...
I am developing my first application with Titanium Alloy. For iOS i use the native iOS trash button, using systemButton="TRASH". For that button i also have an onClick handler, onClick="deleteReckon". However, the deleteReckon method is not called upon clicking the trash button.
This is the "reckonDetails.xml" view for iOS (hence, included in an "ios" directory in the "views" directory) :
<Alloy>
<Window class="container">
<!-- Make a toolbar for delete and info buttons -->
<Toolbar platform="ios" bottom="0" borderTop="true" borderBottom="false">
<!-- The Items tag sets the Toolbar.items property. -->
<Items>
<Button id="info" systemButton="INFO_LIGHT" />
<FlexSpace/>
<Button id="del" onClick="deleteReckon" systemButton="TRASH" />
</Items>
</Toolbar>
<!-- We will display all reckon detail, date, total, ... -->
<View layout='vertical'>
<Label id="dateLabel"></Label>
<!-- ... OTHER LABELS ... -->
</View>
</Window>
</Alloy>
And this is the "reckonDetails.js" controller :
var args = arguments[0] || {};
// Fill in all labels of this view
$.dateLabel.text = "Date: " + args.date || 'Unknown Date';
// ...
function deleteReckon() {
console.log("deleteReckon called"); // Is never displayed
// Delete the selected reckon (this element of the collection)
var selectedReckon = args.selected_reckon;
selectedReckon.destroy();
// Go back to the index page
var args = {};
var indexView = Alloy.createController("index", args).getView();
indexView.open();
}
I put a console.log(...); statement in it to check if the function is called, but it is not..
And finally this is my "reckonDetails.tss" style (not sure if this is relevant for the problem?) :
".container[platform=ios]" : {
backgroundColor: 'white'
},
"Label": {
font: {
fontSize: '20'
},
left: '10'
},
"#dateLabel": {
font: {
fontSize: '30'
},
left: '10'
}
I've tested iOS system TRASH button on Titanium Alloy and Classic project and it's working just fine for me. Please have a look on my code below,
var win = Ti.UI.createWindow({
title : 'Window',
backgroundColor: '#white'
});
var trash = Titanium.UI.createButton({
systemButton: Titanium.UI.iPhone.SystemButton.TRASH,
});
flexSpace = Titanium.UI.createButton({
systemButton:Titanium.UI.iPhone.SystemButton.FLEXIBLE_SPACE
});
var toolbar = Titanium.UI.iOS.createToolbar({
items:[trash, flexSpace],
bottom:0,
borderTop:true,
borderBottom:false
});
win.add(toolbar);
trash.addEventListener('click', function(){
console.log("Treash called");
});
win.open();
Hope you can now find what you are looking for. For more details, please check the documentation from here at http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.SystemButton-property-TRASH and http://docs.appcelerator.com/platform/latest/#!/api/Titanium.UI.iOS.Toolbar.
Thanks
It is easy to use one of the icons available from the standard icon set:
$("#myButton").button({icons: {primary: "ui-icon-locked"}});
But what if I want to add one of my own icons that is not part of the framework icon set?
I thought it would be as easy as giving it your own CSS class with a background image, but that doesn't work:
.fw-button-edit {
background-image: url(edit.png);
}
Any suggestions?
I could also recommend:
.ui-button .ui-icon.your-own-custom-class {
background-image: url(your-path-to-normal-image-file.png);
width: your-icon-width;
height: your-icon-height;
}
.ui-button.ui-state-hover .ui-icon.your-own-custom-class {
background-image: url(your-path-to-highlighted-image-file.png);
width: your-icon-width;
height: your-icon-height;
}
then just type in the JS code:
jQuery('selector-to-your-button').button({
text: false,
icons: {
primary: "you-own-cusom-class" // Custom icon
}});
It worked for me and hope it works for you too!
I believe the reason why his won't work is because you're icon's background-image property is being overridden by the jQuery UI default sprite icon background image. The style in question is:
.ui-state-default .ui-icon {
background-image: url("images/ui-icons_888888_256x240.png");
}
This has higher specificity than your .fw-button-edit selector, thus overriding the background-image proerty. Since they use sprites, the .ui-icon-locked ruleset only contains the background-position needed to get the sprite image's position. I believe using this would work:
.ui-button .ui-icon.fw-button-edit {
background-image: url(edit.png);
}
Or something else with enough specificity. Find out more about CSS specificity here: http://reference.sitepoint.com/css/specificity
This is based on the info provided by Yi Jiang and Panayiotis above, and the jquery ui button sample code:
As I was migrating an earlier JSP application that had a toolbar with images per button, I wanted to have the image inside the button declaration itself rather than create a separate class for each toolbar button.
<div id="toolbarDocs" class="tableCaptionBox">
<strong>Checked Item Actions: </strong>
<button id="btnOpenDocs" data-img="<s:url value="/images/multi.png"/>">Open Documents</button>
<button id="btnEmailDocs" data-img="<s:url value="/images/email.png"/>">Attach to Email</button>
</div>
Of course there were plenty more buttons than just the two above. The s tag above is a struts2 tag, but you could just replace it with any URL
<button id="btnOpenDocs" data-img="/images/multi.png">Open Documents</button>
The below script looks for the attribute data-img from the button tag, and then sets that as the background image for the button.
It temporarily sets ui-icon-bullet (any arbitrary existing style) which then gets changed later.
This class defines the temporary style (better to add further selectors for the specific toolbar if you plan to use this, so that the rest of your page remains unaffected). The actual image will be replaced by the Javascript below:
button.ui-button .ui-icon {
background-image: url(blank.png);
width: 0;
height: 0;
}
and the following Javascript:
$(document).ready(function () {
$("#toolbarDocs button").each(
function() {
$(this).button(
{ text: $(this).attr('data-img').length === 0? true: false, // display label for no image
icons: { primary: "ui-icon-bullet" }
}).css('background-image', "url(" + $(this).attr('data-img') +")")
.css('background-repeat', 'no-repeat');
});
});
The solution at this link worked great for me:
http://www.jquerybyexample.net/2012/09/how-to-assign-custom-image-to-jquery-ui-button.html
$(document).ready(function() {
$("#btnClose")
.text("")
.append("<img height="100" src="logo.png" width="100" />")
.button();
});
My solution to add custom icons to JQuery UI (using sprites):
CSS:
.icon-example {
background-position: 0 0;
}
.ui-state-default .ui-icon.custom {
background-image: url(icons.png);
}
.icon-example defines position of icon in custom icons file. .ui-icon.custom defines the file with custom icons.
Note: You may need to define other JQuery UI classes (like .ui-state-hover) as well.
JavaScript:
$("selector").button({
icons: { primary: "custom icon-example" }
});
Building on msanjay answer I extended this to work for custom icons for both jquery ui buttons and radio buttons as well:
<div id="toolbar">
<button id="btn1" data-img="/images/bla1.png">X</button>
<span id="radioBtns">
<input type="radio" id="radio1" name="radName" data-mode="scroll" data-img="Images/bla2.png"><label for="radio1">S</label>
<input type="radio" id="radio2" name="radName" data-mode="pan" data-img="Images/bla3.png"><label for="radio2">P</label>
</span>
</div>
$('#btn1').button();
$('#radioBtns').buttonset();
loadIconsOnButtons('toolbar');
function loadIconsOnButtons(divName) {
$("#" + divName + " input,#" + divName + " button").each(function() {
var iconUrl = $(this).attr('data-img');
if (iconUrl) {
$(this).button({
text: false,
icons: {
primary: "ui-icon-blank"
}
});
var imageElem, htmlType = $(this).prop('tagName');
if (htmlType==='BUTTON') imageElem=$(this);
if (htmlType==='INPUT') imageElem=$("#" + divName + " [for='" + $(this).attr('id') + "']");
if (imageElem) imageElem.css('background-image', "url(" + iconUrl + ")").css('background-repeat', 'no-repeat');
}
});
}
// HTML
<div id="radioSet" style="margin-top:4px; margin-left:130px;" class="radio">
<input type="radio" id="apple" name="radioSet" value="1"><label for="apple">Apple</label>
<input type="radio" id="mango" name="radioSet" value="2"><label for="mango">Mango</label>
</div>
// JQUERY
// Function to remove the old default Jquery UI Span and add our custom image tag
function AddIconToJQueryUIButton(controlForId)
{
$("label[for='"+ controlForId + "'] > span:first").remove();
$("label[for='"+ controlForId + "']")
.prepend("<img position='fixed' class='ui-button-icon-primary ui-icon' src='/assets/images/" + controlForId + ".png' style=' height: 16px; width: 16px;' />");
}
// We have to call the custom setting to happen after document loads so that Jquery UI controls will be there in place
// Set icons on buttons. pass ids of radio buttons
$(document).ready(function () {
AddIconToJQueryUIButton('apple');
AddIconToJQueryUIButton('mango');
});
// call Jquery UI api to set the default icon and later you can change it
$( "#apple" ).button({ icons: { primary: "ui-icon-gear", secondary: null } });
$( "#mango" ).button({ icons: { primary: "ui-icon-gear", secondary: null } });
in css
.ui-button .ui-icon.custom-class {
background-image: url(your-path-to-normal-image-file.png);
width: your-icon-width;
height: your-icon-height;
}
.ui-state-active .ui-icon.custom-class, .ui-button:active .ui-icon.custom-class {
background-image: url(your-path-to-highlighted-image-file.png);
width: your-icon-width;
height: your-icon-height;
}
in HTML
<button type="button" class="ui-button ui-widget ui-corner-all">
<span class="custom-class"></span> CAPTION TEXT
</button>
in JavaScript
$("selector").button({
icons: { primary: "custom-class" }
});