I have the following hack that draws drop shadows for the various elements that I have:
<template>
<Page>
<TabView>
<TabViewItem title="Tab 1">
<StackLayout #loaded="addShadow">
<Label text="This box does have a shadow." />
</StackLayout>
</TabViewItem>
<TabViewItem title="Tab 2">
<StackLayout>
<Label text="This box doesn't have a shadow." />
</StackLayout>
</TabViewItem>
</TabView>
</Page>
</template>
<script>
export default {
methods: {
addShadow(event) {
if (event.object.ios) {
event.object.ios.layer.masksToBounds = false;
event.object.ios.layer.shadowOpacity = 0.5;
event.object.ios.layer.shadowRadius = 5.0;
event.object.ios.layer.shadowColor = new Color('#000000').ios.CGColor;
event.object.ios.layer.shadowOffset = CGSizeMake(0.0, 2.0);
}
}
}
}
</script>
<style scoped>
StackLayout {
background: #ffffff;
padding: 16;
margin: 16;
}
</style>
However, while the shadow looks perfect, it does not initially appear when the tab is first accessed. I have to first visit the second tab, and only after returning to the first tab, does the drop shadow get drawn.
I assume this is because I need to invoke something to redraw the layer after adding the shadow, but I cannot figure out how to do that. I've tried event.object.ios.layer.setNeedsDisplay() but it has no effect.
How can I ensure the shadow displays on the first tab render?
Related
Well going through {N} tutorial I want to achieve this :
But I have trouble showing this delete button.
There is no problem with the image it shows well somewhere else and I also tried putting a Label instead but same result.
Rad Listview component :
<RadListView row="1" [items]="groceryList"
swipeActions="true" (itemSwipeProgressStarted)="onSwipeCellStarted($event)">
<ng-template let-item="item">
<Label [text]="item.name" class="p-15"></Label>
</ng-template>
<GridLayout *tkListItemSwipeTemplate columns="*, auto">
<StackLayout id="delete-view" col="1" (tap)="delete($event)" class="delete-view">
<Image src="~/images/delete.png" ></Image>
</StackLayout>
</GridLayout>
</RadListView>
CSS :
.delete-view {
background-color: #CB1D00;
padding: 20;
}
.delete-view Image {
color: white;
height: 25;
}
TS
onSwipeCellStarted(args: ListViewEventData) {
var swipeLimits = args.data.swipeLimits;
var swipeView = args.object;
var rightItem = swipeView.getViewById<View>("delete-view");
swipeLimits.right = rightItem.getMeasuredWidth();
swipeLimits.left = 0;
swipeLimits.threshold = rightItem.getMeasuredWidth() / 2;
}
delete(args: ListViewEventData) {
let grocery = <Grocery>args.object.bindingContext;
this.groceryService.delete(grocery.id)
.subscribe(() => {
let index = this.groceryList.indexOf(grocery);
this.groceryList.splice(index, 1);
});
}
Deletion feature works well but all what i am getting when swiping is this :
What am I getting wrong here ?
I spent several days earlier this month wrestling with similar issues with RadListView, especially on iOS. It seems to defy logic. I ended up using a negative padding to get to where I could see my labels and icons. If that doesn't help, try removing height: from your css.
I have a radautocomplete in one of my pages and I'm using bottom-navigation in my app.
The first time I navigate to that page is fine, but after that, when I navigate to that page, the suggestions menu automatically pops open as if I had typed something in the autocomplete but I have not. I even put a textfields above that in my form to steal the focus but that didn't make things any better.
Here is a playground sample
In case playground breaks in the future:
App.vue
<template>
<Page actionBarHidden="true">
<BottomNavigation :selectedIndex="activePage">
<TabStrip>
<TabStripItem>
<label text="0" />
</TabStripItem>
<TabStripItem>
<label text="1" />
</TabStripItem>
</TabStrip>
<TabContentItem>
<button text="go to 1" #tap="activePage=1" />
</TabContentItem>
<TabContentItem>
<StackLayout>
<TextField v-model="textFieldValue" hint="Enter text..."
backgroundColor="lightgray" />
<RadAutoCompleteTextView ref="autocomplete"
:items="choices" backgroundColor="lightgray"
completionMode="Contains" returnKeyType="done"
width="100%" borderRadius="5" />
</StackLayout>
</TabContentItem>
</BottomNavigation>
</Page>
</template>
<script>
import {
ObservableArray
} from "tns-core-modules/data/observable-array";
import {
TokenModel
} from "nativescript-ui-autocomplete";
export default {
data() {
return {
textFieldValue: "",
choices: new ObservableArray(
["one", "two", "three"].map(r => new TokenModel(r))
),
activePage: 0
};
}
};
</script>
<style scoped>
TabContentItem>* {
font-size: 30;
text-align: center;
vertical-align: center;
}
</style>
app.js
import Vue from 'nativescript-vue';
import App from './components/App';
import RadAutoComplete from 'nativescript-ui-autocomplete/vue';
Vue.use(RadAutoComplete);
new Vue({ render: h => h('frame', [h(App)]) }).$start();
I guess the issue is specific to Android, iOS seem to work fine. You may raise an issue at Github, meanwhile a possible workaround is to set visibility on suggestion view on unloaded event, toggle it back on textChanged event.
Updated Playground Sample 1
Update
Changing visibility seems to hide the suggestion view but still occupy the same so components below auto complete field becomes inaccessible. I believe setSuggestionViewHeight(...) may solve this.
Updated Playground Sample 2
Is there a way to make a view 'transparent' to any user interactions? For example I have a view (with transparent background) and a button under that view. I want the user could tap the button under that view. If I have a scroller view under that view I want the user interacts with scroller when scroll over that view, so the view doesn't interfere or intercept user's gestures. But only this view should be transparent to user's interactions not its children. So, if I have a button inside that view it behaves normally.
Example XML:
<AbsoluteLayout width="100%" height="100%">
<Button text="Button1" tap="onTap1" />
<GridLayout width="100%" height="100%" backgroundColor="transparent">
<Button text="Button2" tap="onTap2" horizontalAlignment="center" verticalAlignment="center"/>
</GridLayout>
</AbsoluteLayout>
Thank you for your help.
You have multiple approaches to make a view change its color in NativeScript.
For example you can directly change its backgroundColor. Another oiption is to use animation and third option is to use CSS-animation.
Here is a basic example for the first two options.
page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout>
<GridLayout width="300" height="300" id="myGrid" backgroundColor="transparent">
</GridLayout>
<Button text="Tap me" tap="onTap" />
<Button text="Or Tap me" tap="onAnotherTap" />
</StackLayout>
</Page>
page.js
import { EventData } from "data/observable";
import { Page } from "ui/page";
import { HelloWorldModel } from "./main-view-model";
import { GridLayout } from "ui/layouts/grid-layout";
import { Color } from "color";
var myGridView;
export function navigatingTo(args: EventData) {
var page = <Page>args.object;
page.bindingContext = new HelloWorldModel();
// get refference to the view using its id
myGridView = <GridLayout>page.getViewById("myGrid");
}
export function onTap(args:EventData) {
var color = new Color("#FF0000");
myGridView.backgroundColor = color;
}
export function onAnotherTap(args:EventData) {
myGridView.animate({
backgroundColor: new Color("#3D5AFE"),
duration: 3000
});
}
All of the options can be found described in NativeScript documenation
The default textbox has a bottom border.
How can I get a textView or textField in Native Script XML without that bottom border?
Based on the suggestion by Nikolay, the following should do it in the stylesheet
background-color: transparent;
border-color: transparent;
One possible decision could be to remove textfield and textview border-bottom is to set background color. This will color up the border too. I will give you an example bellow
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo">
<StackLayout backgroundColor="red">
<Label text="Tap the button" class="title"/>
<Button text="TAP" tap="{{ onTap }}" />
<Label text="{{ message }}" class="message" textWrap="true"/>
<TextField hint="" id="tfield" text="tests textfield"/>
<TextView hint="" id="tview" text="tests textView" editable="true" style="border-color:white; " />
</StackLayout>
</Page>
main-page.js
var main_view_model_1 = require("./main-view-model");
var color_1 = require('color');
// Event handler for Page "navigatingTo" event attached in main-page.xml
function navigatingTo(args) {
// Get the event sender
var page = args.object;
var tf = page.getViewById("tfield");
tf.borderColor = new color_1.Color("#ffffff");
tf.backgroundColor = new color_1.Color(100, 255, 0, 0);
var tv = page.getViewById("tview");
tv.borderColor = new color_1.Color("#ffffff");
tv.backgroundColor = new color_1.Color(100, 255, 0, 0);
page.bindingContext = new main_view_model_1.HelloWorldModel();
}
exports.navigatingTo = navigatingTo;
I using GridView Nativescript to arrange the UI and I want to set css into specific button or label dynamically. How can I find inside label when outside button is trigger and I tried using getViewById method but always get empty result. Isn't got any method to find it ?
var gridview;
exports.onPageLoaded = function (args) {
page = args.object;
gridview = page.getViewById("gridview");
};
exports.onSelectedIndexChanged = function(args){
var totalMatch = 0;
var btn = args.object;
var index = btn.index;
var a = gridview.getViewById("25");
btn.backgroundColor = "red";
btn.color = "white";
};
<GridLayout columns="*,1,*,1,*" rows="auto" borderWidth="1" borderColor="#DBDBDB" borderRadius = "3" >
<Button text="selectALL" index="0" tap="onSelectedIndexChanged" backgroundColor= "red" id ="btnSelectAll" color="white" borderRadius="3" />
<Button text="UnselectAll" index="1" col="2" tap="onSelectedIndexChanged" backgroundColor= "white" id ="btnUnSelectAll" borderRadius = "3" />
<Border col="1" borderWidth="1" borderColor="#DBDBDB" />
<Border col="3" borderWidth="1" borderColor="#DBDBDB" />
</GridLayout>
<gv:GridView items="{{ items }}" verticalSpacing="3" horizontalSpacing="3" colWidth="100" rowHeight="50" padding="3" id="gridview" height="400">
<gv:GridView.itemTemplate>
<GridLayout backgroundColor="#ffffff" style="border-width:3px;border-color:#696969;border-radius:5">
<Button text="{{ Name }}" id="{{ Id }}" index="{{ Index }}" tap="onGridViewItemTap" backgroundColor= "white" color="red" style="background-size:100% 100%;background-repeat:no-repeat;background-image:url('~/images/drawable-hdpi-v4/spt_fiter_checked.png')" borderWidth="1" borderColor="#DBDBDB" borderRadius = "5"/>
</GridLayout>
</gv:GridView.itemTemplate>
</gv:GridView>
After my understanding, what you are trying to do is:
press the button in the GridLayout
trigger the onSelectedIndexChanged function
Access the button with id="25"
Modify the button
First, I would like to point out that it is not recommended to access views by ids, especially when you have a complex UI structure. I would suggest that you use bindings. I am not sure what exactly you would like to modify, so I will assume that you would like to change the background property of the button. In this case, you can bind an Observable object in the code to the background property in the XML. Then in the function onSelectedIndexChanged, you can modify the object in the code by setting a new color. Since it is observable, it will notify all of the listeners for the modification. And in our case - the property in the XML.
Here I am sending you a simple example:
main-page.xml
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="onPageLoaded">
<GridLayout rows="auto,auto" >
<Button text="Click to Change Color" row="0" tap="onSelectedIndexChanged"/>
<Button text="Button" row="1" backgroundColor="{{color}}"/>
</GridLayout>
</Page>
main-page.js
var observable = require("data/observable");
var json={color:'red'};
var changeCss = new observable.Observable(json);
var gridview;
exports.onPageLoaded = function (args) {
page = args.object;
page.bindingContext=changeCss;
};
exports.onSelectedIndexChanged = function(args){
changeCss.set("color","blue");
};
I hope this will give you some directions.