How can I deselect an item from ListView in cascade? - blackberry

I'm developing a BlackBerry 10 mobile application using the Momentics IDE (native SDK).
I have a simple ListView and I want to change the background of a specific item when clicked according to the selection status. I thought th code below will work but it doesn't, any one can help one this ?
ListView{
id: simpleList
dataModel: groupDataModel
listItemComponents: [
ListItemComponent {
type: "item"
SQLvListItem {
id: containerItem
itemLabel: ListItemData.label
// Item Label Style
itemFontSize: ListItemData.fontSize
itemFontName: ListItemData.fontName
itemFontStyle: ListItemData.fontStyle
itemFontColor: containerItem.ListItem.selected ? ListItemData.fontColorSelected : ListItemData.fontColor
//Item background
containerBorderColor: ListItemData.borderColor
containerBackgroundColor: containerItem.ListItem.selected ? ListItemData.backgroundColorSelected : ListItemData.backgroundColor
}
}
]
onTriggered: {
var selectedItem = dataModel.data(indexPath);
if (selected() == indexPath){
select(indexPath, false);
dataModel.itemUpdated(indexPath)
}
else{
select(indexPath, true);
}
}
}
PS: the "SQLvListItem" is a custom item which I created

In your SQLvListItem, add a property that is a bool for "IsSelected" and add containerSelectedBackgroundColor with containerUnselectedBackgroundColor and itemSelectedFontColor with itemUnselectedFontColor.
Then you can make a function like so:
function selectedBackground(selectedItem){
if(selectedItem.isSelected){
selectedItem.itemFontColor: selectedItem.itemSelectedFontColor;
selectedItem.containerBackgroundColor: selectedItem.itemSelectedFontColor;
}
else{
selectedItem.itemFontColor: selectedItem.itemUnselectedFontColor;
selectedItem.containerBackgroundColor: selectedItem.itemUnselectedFontColor;
}
}
That way you have variables to store the selectedColor and unselectedColor for both font and background, and then you can swap them out on the fly. When it gets selected, just flag the isSelected as true when it is selected, and false when it isn't.
I only have a snippet of your code to go off of, so I don't know for sure if this will work, but it's worth a shot!

Actually it was so simple, you just need to use toggleSelection() function which toggles selection on an item ; if the item is selected, it becomes deselected and if the item is deselected, it becomes selected.
ListView{
id: simpleList
dataModel: groupDataModel
listItemComponents: [
ListItemComponent {
type: "item"
SQLvListItem {
id: containerItem
itemLabel: ListItemData.label
// Item Label Style
itemFontSize: ListItemData.fontSize
itemFontName: ListItemData.fontName
itemFontStyle: ListItemData.fontStyle
itemFontColor: containerItem.ListItem.selected ? ListItemData.fontColorSelected : ListItemData.fontColor
//Item background
containerBorderColor: ListItemData.borderColor
containerBackgroundColor: containerItem.ListItem.selected ? ListItemData.backgroundColorSelected : ListItemData.backgroundColor
}
}
]
onTriggered: {
var selectedItem = dataModel.data(indexPath);
toggleSelection(indexPath) // (solution 1)
// Or you can use also
select(indexPath, (!isSelected(indexPath))) // (solution 2)
}
}

Related

Issue with pass by value vs pass by reference in Swift?

I'm new to Swift but not new to iOS dev. I'm having an issue that I believe is caused by pass by value.
Below code is in the VC and works fine when tapping each button, i.e. each button changes background to show if it's selected or not.
button.isSelected = card.isChosen // button is selected when the card is chosen
if button.isSelected {
button.setBackgroundColor(color: UIColor.darkGray, forState: UIControlState.selected)
}
I have an issue in the game logic which is a struct. Struct contains an array of type Card which is really just a deck of cards and maps back to the UIButtons. When a card(UIButton) in the VC is touched, it calls a method (chooseCard) in the Struct. Among other things, this action will toggle if the card is selected by setting the card.isSelected = !card.isSelected and maps back to the UI to indicate if the card is selected or not. All of this works fine so far.
When 3 cards have been selected, it calls some match logic, which is currently just stubbed out. If there was no match, each of the cards .isSelected is set to false so that in the UI those cards will no longer appear selected. This is what is not working and I can't figure out why. My hunch is that I'm doing something wrong in the way I'm dealing with pass by value since the logic object is a struct. After 3 cards are selected and they are not matched (they won't since it's only stubbed), each card.isSelected should be set back to false, but they are still showing selected in the UI. I set a breakpoint in the VC and it shows the card.isSelected is still set to true. VC has has a setGame property which has access to the array of cards. Here is the relevant code...any help is appreciated!
struct SetGame {
private(set) var cards = [Card]()
mutating public func chooseCard(at index: Int) {
//TODO: Assertion here for index being < cards.count
print("chooseCard(at index: \(index)")
cards[index].isChosen = !cards[index].isChosen // toggle isChosen when card is selected
if !cards[index].isMatched && cards[index].isChosen {
//print("Card not matched, so we're good to go...")
for var card in cards {
if card.isChosen {
matchingCards.append(card)
// see if we have enough cards to match
if matchingCards.count > 2 {
//TODO: Need to call match logic here and set each matched card to .isMatched = true if matched
if card.isMatched {
print("Yay, matched!")
} else {
print("Card is not matched, flipping back over")
/*** THIS LINE NOT REFLECTING IN THE UI! ***/
card.isChosen = !card.isChosen // flip the unmatched card back over
}
}
}
}
matchingCards.removeAll() // clear out all the cards from the matching
} else {
print("Card is either matched or being deselected...")
}
}
Your problem is that Card is a struct, so this line:
for var card in cards {
creates a copy of each card in cards, so setting any properties on that copy will not modify the card in your cards array.
To fix this, loop over the indices of the array and refer to the cards as cards[idx]:
struct SetGame {
private(set) var cards = [Card]()
mutating public func chooseCard(at index: Int) {
//TODO: Assertion here for index being < cards.count
print("chooseCard(at index: \(index)")
cards[index].isChosen = !cards[index].isChosen // toggle isChosen when card is selected
if !cards[index].isMatched && cards[index].isChosen {
//print("Card not matched, so we're good to go...")
for idx in cards.indices {
if cards[idx].isChosen {
matchingCards.append(cards[idx])
// see if we have enough cards to match
if matchingCards.count > 2 {
//TODO: Need to call match logic here and set each matched card to .isMatched = true if matched
if cards[idx].isMatched {
print("Yay, matched!")
} else {
print("Card is not matched, flipping back over")
/*** THIS LINE NOT REFLECTING IN THE UI! ***/
cards[idx].isChosen = !cards[idx].isChosen // flip the unmatched card back over
}
}
}
}
matchingCards.removeAll() // clear out all the cards from the matching
} else {
print("Card is either matched or being deselected...")
}
}
or consider making Card a class so that when you are referring to a Card you know you are referring to the same object.

How to store button tags in a variable?

I have 5 buttons representing cities, I have assigned them tags via Attribute Inspector as follows, CityA as 0,.......CityE as 4.
Is there a way I can store these tags into a variable cityTag and make sure that if none of button is pressed while saving, I can send a message "Please select a city"
I created an action with multiple buttons, but I have no idea how to create a variable and assign tags to it.
For better readability of code yourcould define an Enum for that case which represents the name and tag as well :
for example:
enum City: Int {
case .cityA,
case .cityB,
case .cityC
}
You can store them in an Array:
var cities: [City] = []
To set a city:
if let cityA: City = City(rawValue: button.tag) {
cities.append(cityA)
}
To read the Int value:
let rawValue: Int = cityA.rawValue
Since you are adding tags via the attribute inspector, you can access the tapped button's tag via sender.tag property!
Initially create an NSMutableArray (that will hold a the tags of all buttons pressed) but will obviously be empty at the start! You can access the tag with the sender.tag property in the IBAction. If your NSMutableArray doesn't contain a tag when you try to save, you can show the alert.
Initialise citytag = -1. Change the value of citytag when you press a button like citytag = sender.tag and keep a check if citytag == -1 then send a message please select a city else selected city is ###
you can try this:
func checkbuttons -> BOOL {
var countBtn = 0
for view in self.view.subviews as [UIView]
{
if let btn = view as? UIButton
{
if btn.isSelected
{
countBtn = countBtn + 1
}
}
}
if(countBtn > 0)
{
return true
}
else
{
return false
}
}
On basis of return you will know button selected or not.
Hope it will help you

BB10 Cascades: how it`s made?

How implement many custom ListItems, like its implemented in standart blackberry calendar app.
The following screenshot shows what I mean
Especially I interested what is the second control with right arrow.
Thanks.
You can have multiple "types" of list items.
Attach your different types of listItemComponents each with a different type. e.g.
listItemComponents: [
ListItemComponent {
type: "itemA"
Container {
Label {
text: ListItemData.title
textStyle.color: Color.Blue
}
}
},
ListItemComponent {
type: "itemB"
Container {
Label {
text: ListItemData.title
textStyle.color: Color.Red
}
}
}
]
Then add this function to your listview (I'm using a property of "mytype" but you could check any property of the data model or even base it on the indexpath):
function itemType(data, indexPath) {
if (data.mytype == "typea") {
return "itemA";
} else {
return "itemB";
}
}
Now when you add your data to your datamodel make sure you specify "mytype" and the listview will automatically use the ListItemComponent for the relative type.
You can easily have different sized list items, different designs even have them work with different data structures.

Accessing the Selected property on TitleBar tabs

I am using the Application Layout control and have tabs in the TitleBar. I want to change the style of the tab if it is selected. I am currently doing it by comparing the value of the tab to a sessionScope variable I am setting when the tab is clicked.
I saw something (though I can't find it now) about using the Selected property of the Basic Node I am using for the tab. How would I access that in SSJS so that I can do something like this?
if(thisnode.selected) {
return "lotusTabs liActive";
} else {
return "lotusTabs li";
}
Thanks.
You can also access the tabs programmatically:
var layout = getComponent("layoutId");
var selectedTab = null;
var tabs = layout.getConfiguration().getTitleBarTabs();
for (var tab in tabs) {
if (tab.getSelected()) {
selectedTab = tab;
}
}
The following CSS rule will target the selected title tab:
div.lotusTitleBar ul.lotusTabs li.lotusSelected {
// your code here
}

recognizing button presses in actionscript

In a mini flash game, I have a few different level select buttons, and they all attach to one "levelChange()" function, and I'm just wondering if there is an attribute that stores which button was pressed or how to determine which was pressed if not.
Thanks
try the currentTarget property of MouseEvent example:
function buttonClick(event:MouseEvent):void
{
trace(event.currentTarget);
}
I recommend you store your buttons in variables outside your function like so:
var levelOne:MovieClip = levelOne;
So you can later call upon them like this:
function buttonClick(event:MouseEvent):void
{
if (event.currentTarget == levelOne) {
trace("level one selected");
else if (event.currentTarget == levelTwo) {
trace("level two selected");
}
}
If you're using AS3 you can add a switch statement in your levelChange() function.
For example.... if you have 2 buttons, one with the instance name of "level1", and the other "level2".
function levelChange( me:MouseEvent ):void
{
switch( me.currentTarget.name )
{
case "level1":
// Go to Level 1 here.
case "level2":
// Go to Level 2 here.
}
}

Resources