Flex 4 custom component with children inserted directly into view stack - flex4

I give up. Hopefully I am just missing something easy, but I feel like I am pulling teeth trying to get this to work. All I want is a custom 'wizard' component whose children are placed within a ViewStack and beneath the ViewStack there is a next and back button. Here are some code excerpts to illustrate my approach:
WizardGroup.as:
[SkinPart(required="true")]
public var nextBt:Button = new Button();
[SkinPart(required="true")]
public var backBt:Button = new Button();
[SkinPart(required="true")]
public var stack:ViewStackSpark = new ViewStackSpark();
WizardGroupSkin.mxml:
<s:VGroup width="100%" height="100%"
paddingBottom="10" paddingTop="10" paddingLeft="10" paddingRight="10">
<container:ViewStackSpark id="stack" width="100%" height="100%">
<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0"/>
</container:ViewStackSpark>
<s:HGroup horizontalAlign="right" width="100%">
<s:Button id="nextBt" label="Next" enabled="{hostComponent.permitNext}" enabled.last="false"/>
<s:Button id="backBt" label="Back" enabled="{hostComponent.permitBack}" enabled.first="false"/>
</s:HGroup>
</s:VGroup>
While this comes very close to working, the major problem is that the children of the WizardGroup component are not added as children of the viewstack. Instead, they are added as children of the contentGroup. So the viewstack will always only have one child: contentGroup.
I also tried the approach of binding the contents of the view stack to the children of contentGroup, but with Spark containers, there is no way to access an array of children or array of elements (ie, there is no contentGroup.getChildren() or contentGroup.getElements())
Any ideas? Thanks everyone.

I finally figured it out. The trick is to set the default property of the WizardGroup to a public member array I am calling "content"
[DefaultProperty("content")]
public class WizardGroup extends TitleWindow
{
[SkinPart(required="true")]
public var nextBt:Button = new Button();
[SkinPart(required="true")]
public var backBt:Button = new Button();
[Bindable]
public var content:Array;
And then within the skin, bind the content of the viewstack to the hostComponent's content array:
<s:VGroup width="100%" height="100%"
paddingBottom="10" paddingTop="10" paddingLeft="10" paddingRight="10">
<container:ViewStackSpark id="stack" width="100%" height="100%" content="{hostComponent.content}"/>
<s:HGroup horizontalAlign="right" width="100%">
<s:Button id="nextBt" label="Next" enabled="{hostComponent.permitNext}" enabled.last="false"/>
<s:Button id="backBt" label="Back" enabled="{hostComponent.permitBack}" enabled.first="false"/>
</s:HGroup>
</s:VGroup>

Related

radautocomplete menu pops open when navigating with bottom navigation

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

NativeScript: how to make view 'transparent' for any user interactions

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

Telerik + RadChart: How to call a Server side Method on ClientSeriesClick Event

I have implemented a module where i am using telerik red bar chart.And i want to generate another bar graph on click on bar of existing chart i.e there are two charts one is shown on page load and second is detailed one which is shown after click on any bar of first chart.Have mentioned my code below:-
<asp:Panel ID="Panel1" runat="server">
<telerik:radhtmlchart id="RadHtmlChart2" runat="server" width="600" height="400"
onclientseriesclicked="OnClientSeriesClicked">
<%-- <ClientEvents OnSeriesClick="OnSeriesClick" />--%>
<PlotArea>
<Series>
<telerik:ColumnSeries Name="Series 1">
<SeriesItems>
<telerik:CategorySeriesItem Y="30" />
<telerik:CategorySeriesItem Y="10" />
<telerik:CategorySeriesItem Y="20" />
</SeriesItems>
</telerik:ColumnSeries>
</Series>
<XAxis>
<LabelsAppearance RotationAngle="33">
</LabelsAppearance>
<Items>
<telerik:AxisItem LabelText="Item 1" />
<telerik:AxisItem LabelText="Item 2" />
<telerik:AxisItem LabelText="Item 3" />
</Items>
</XAxis>
</PlotArea>
</telerik:radhtmlchart>
<asp:Panel ID="Panel2" runat="server">
//My Second chart Shown Here
</asp:Panel>
</asp:Panel>
Above code i have used for generating my first chart
Second Chart which i am trying to fill in my asp Panel2.
protected void RadAjaxManager1_AjaxRequest(object sender, Telerik.Web.UI.AjaxRequestEventArgs e)
{
RadHtmlChart chart = new RadHtmlChart();
chart.ID = "chart2";
ColumnSeries cs = new ColumnSeries();
CategorySeriesItem csi = new CategorySeriesItem();
cs.DataFieldY = "TOTALCALLS";
cs.SeriesItems.Add(csi);
chart.PlotArea.Series.Add(cs);
Panel2.Controls.Add(chart);
}
My Ajax Call
<telerik:radcodeblock id="RadCodeBlock1" runat="server">
<script>
function getAjaxManager() {
return $find("<%=RadAjaxManager1.ClientID%>");
}
</script>
</telerik:radcodeblock>
I just want to fill second bar graph i.e i want to use client seriesevent for calling my server side method in red chart
Invoke an AJAX request through the RadAjaxManager client-side API: http://docs.telerik.com/devtools/aspnet-ajax/controls/ajax/client-side-programming/overview. Something like:
getAjaxManager().ajaxRequest("someOptionalArgument");
You can find similar code in the drilldown chart demo: http://demos.telerik.com/aspnet-ajax/htmlchart/examples/drilldownchart/defaultcs.aspx. It changes the datasource of the current chart but the client-side logic is the same.
On the server, just make sure to recreate the second chart with each subsequent postback, as any other server control.

Group gets height from original image, not the scaled image

In my app I import a twitter timeline. Some tweets contain images, some don't. Also the height of the imqages is variabel. I have a set width of 90% to make sure the images fit in the group (with a vertical layout), but no matter what I do, the group gets it's height from the original image, not the scaled height. I tried setting variableRowHeight="true", but that doesn't seem to do anything.Here is some sample code:
<s:List id="list" y="0" width="90%" height="954" dataProvider="{tweets}" horizontalCenter="0">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:itemRenderer>
<fx:Component>
<s:ItemRenderer>
<s:Group width="100%">
<s:Label id="twitlabel" text="{tweetImage.height}"
width="100%"
styleName="tweetlist"/>
<s:Image id="tweetImage" y="{twitlabel.height}" width="90%" horizontalCenter="0" scaleMode="letterbox" smooth="true" source="{data.entities.media[0].media_url}"/>
</s:Group>
</s:ItemRenderer>
</fx:Component>
</s:itemRenderer>
The question is, how can I get the group to set it's height to the scaled image height?
First set the "complete" event handler for your Image and an id for your Group:
<s:Group id="tweetImageGroup" width="100%">
<s:Image id="tweetImage" y="{twitlabel.height}" horizontalCenter="0" scaleMode="letterbox" smooth="true" source="{data.entities.media[0].media_url}" complete="tweetImage_completeHandler(event)"/>
Then set the width after the image has completed loading:
protected function tweetImage_completeHandler(event:Event):void{
tweetImageGroup.height = event.currentTarget.measuredHeight;
}
This might need some adjusting but should work if I understood your problem correctly.

Appcelerator alloy views slide

I am using the Alloy MVC framework over Titanium and want to make a slideshow between views. When I swipe on the screen, I want to display the next/previous view with a slide effect from right to left or left to right.
I am using this code:
A tab in my index.xml:
<Tab title="Bilan" icon="KS_nav_ui.png">
<Window title="Bilan" id="bilanTab" onSwipe="doBilanSwipe">
</Window>
</Tab>
The question view dynamically added and filled inside bilanTab:
<Alloy>
<Collection src="ReponsePossible">
<View id="questionContainer" class="container">
<Label id="questionText" />
<Button id="buttonNextQuestion">Question suivante</Button>
</View>
</Alloy>
and my two functions (3 with prevQuestion not printed here) inside index.js controller:
var previousQuestion;
var nextQuestion;
function doBilanSwipe(e){
if (e.direction == 'left'){
nextQuestion();
}
else if (e.direction == 'right'){
prevQuestion();
}
}
function nextQuestion(){
if (questionsCurrentIndex < questions.length-1){
questionsCurrentIndex++;
$.previous = previousQuestion;
$.next = Alloy.createController('question', questions.at(questionsCurrentIndex));
nextQuestion = $.next;
$.next.questionContainer.left = 320;
$.bilanTab.add($.next.questionContainer);
$.next.questionContainer.animate({left:0, duration:200});
$.previous.questionContainer.animate({left:-320, duration:200},function(){
$.previous = previousQuestion;
$.next = nextQuestion;
$.bilanTab.remove($.previous.questionContainer);
previousQuestion = $.next;
$.previous.destroy();
});
}
}
My problem is that first animation (first view moving to the left) is ok but after that, the next view just appear without any animation.
Could someone help? Thanks!
There is already the Titanium.UI.ScrollableView that does this exact thing, for all platforms.
Use it in Alloy like this:
<Alloy>
<Window id="win">
<ScrollableView id="scrollableView" showPagingControl="true">
<View id="view1" backgroundColor="#123" />
<View id="view2" backgroundColor="#246" />
<View id="view3" backgroundColor="#48b" />
</ScrollableView>
</Window>
</Alloy>
You can dynamically add views to it inside the controller like this:
$.scrollableView.addView(Ti.UI.createView({ // your custom attributes here});

Resources