Foreach loop not working in android for custom object - android-listview

I am trying to store the count of number of times an item from a list view is clicked in a custom array list but in my code the quantity of only the first clicked item is increasing and if i click on any other item then it gets added to the list view instead of increasing the quantity. Please tell me if you know any other method to get the count. Thanks
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Flowers item = (Flowers) parent.getAdapter().getItem(position);
if(item == null)
{
Toast.makeText(getBaseContext(),"item is null",Toast.LENGTH_LONG).show();
}else {
selectedItems items = new selectedItems();
items.setName(item.getName());
items.setCategory(item.getCategory());
Counter counter = new Counter();
if(selectedItemsArrayList.isEmpty())
{
counter.CartItemPosition = 0;
counter.MenuItemPosition = position;
counter.quantity = 1;
items.setQuantity(counter.quantity);
count.add(counter);
selectedItemsArrayList.add(items);
}
else
{
for(Counter c : count)
{
if(c.MenuItemPosition == position)
{
c.quantity = c.quantity + 1;
int i = c.CartItemPosition;
selectedItemsArrayList.get(i).setQuantity(c.quantity);
break;
}
else
{
Counter obj = new Counter();
obj.MenuItemPosition = position;
obj.CartItemPosition++;
obj.quantity=1;
count.add(obj);
items.setQuantity(obj.quantity);
selectedItemsArrayList.add(items);
return;
}
}
}
}
}
});
and my Counter class is
public class Counter {
public int CartItemPosition;
public int MenuItemPosition;
public int quantity;}

Related

How to save boolean properly on Playerprefs?

I want to make a shop system if I buy the items, the items will be saved on Playerprefs, no need to buy again when I restart or re-open the game, for that I already make it to setInt but I don't know when I call getInt. I tried to call it in the start method with a new int index but it doesn't work. This my script
for store the itemsType
[System.Serializable]
public class m_ShopItem
{
public Sprite theIcon;
public int price;
public bool isBuyed;
}
Then I make a list
public List<m_ShopItem> ShopItemsList = new List<m_ShopItem>();
[SerializeField] GameObject ShopPanel;
[SerializeField] Transform theContent;
GameObject g;
Button buyBtn;
public GameObject itemTemplate;
private void Start()
{
for (int i = 0; i < ShopItemsList.Count; i++)
{
g = Instantiate(itemTemplate, theContent);
g.transform.GetChild(0).GetComponent<Image>().sprite = ShopItemsList[i].theIcon;
g.transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = ShopItemsList[i].price.ToString();
buyBtn = g.transform.GetChild(2).GetComponent<Button>();
if (ShopItemsList[i].isBuyed)
{
DisableBuyButton();
}
ShopItemsList[i].isBuyed = PlayerPrefs.GetInt("isBuyed") == 1 ? true : false;// i call it Get here
Debug.Log(ShopItemsList[i].isBuyed);
buyBtn.AddEventListener(i, OnShopItemBtnClicked);
}
}
void OnShopItemBtnClicked(int itemIndex)
{
if (m_shopManager.Instance.HasEnoughCoins(ShopItemsList[itemIndex].price))
{
m_shopManager.Instance.UseCoins(ShopItemsList[itemIndex].price);
//purchase Item
ShopItemsList[itemIndex].isBuyed = true;
PlayerPrefs.SetInt("isBuyed", ShopItemsList[itemIndex].isBuyed ? 1 : 0); // SetThe Int here when button clicked and buy the item
//disable the button
buyBtn = theContent.GetChild(itemIndex).GetChild(2).GetComponent<Button>();
DisableBuyButton();
//add avatar
m_Profile.Instance.AddBallType(ShopItemsList[itemIndex].theIcon);
}
else
{
//NoCoinsAnim.SetTrigger("NoCoins");
Debug.Log("You don't have enough coins!!");
}
}
void DisableBuyButton()
{
buyBtn.interactable = false;
buyBtn.transform.GetChild(0).GetComponent<Text>().text = "PURCHASED";
}
but the result is the same I have to rebuy when going to the main menu or restart the game.
Can anyone tell me what's wrong with my script?
Your current problem is that you create only one PlayerPrefs Object with the value being equal to 1 or 0.
So if you buy only one of your shop items all of them get unlocked. Because you only Check if the PlayerPrefs is true(1) or false (0).
To fix that we would need to create a List of unique PlayerPrefs equal to the amount of shop items. We can do that if we add the index in the ShopItemsList to the isBuyed name.
Create initial Playerprefs:
// Called before the Start Function
private void Awake() {
// Loop through all shopping Items
for (int i = 0; i < ShopItemsList.Count; i++) {
// Check if the Item was already bought
bool bought = PlayerPrefs.GetInt("isBuyed"+i) == 1 ? true : false;
// If it was we can't reset the score.
if (!bought) {
// Create a different PlayerPrefs for each Item in the Shop.
PlayerPrefs.SetInt("isBuyed"+i, ShopItemsList[i].isBuyed ? 1 : 0);
}
}
}
...
Now we can check for that PlayerPrefs instead of checking for just once in Start().
Check if Items were bought:
private void Start() {
// Loop through all shopping Items
for (int i = 0; i < ShopItemsList.Count; i++) {
...
// Actualize our values so already bought items can't be bought again
ShopItemsList[i].isBuyed = PlayerPrefs.GetInt("isBuyed"+i) == 1 ? true : false;
// Check if the item was bought
if (ShopItemsList[i].isBuyed) {
DisableBuyButton();
}
...
}
}
We also need to make sure that we set the right PlayerPrefs when we buy a Product from the Shop. To ensure that we can just add the itemIndex parameter we get from the function and add that to the isBuyed name.
Buying Items:
void OnShopItemBtnClicked(int itemIndex) {
...
// Buy the Item.
ShopItemsList[itemIndex].isBuyed = true;
PlayerPrefs.SetInt("isBuyed"+itemIndex, ShopItemsList[itemIndex].isBuyed ? 1 : 0);
...
}

Item in ScrollView is not seen in Scene, but it shows in hierarchy

I am trying to display a list, generated dinamically. I created a prefab with the things I need in it (a TextView, 3 TMP_InputFields and 2 Buttons.)
To manage the different list items, I created a script (SkillManager, since the items represents skill the player can choose), which I attached to the prefab.
Then, I add every item (currently I am adding only one for testing purposes) to a List, iterate that list, and add the prefab to the Content of a ScrollView:
for(int i = 0; i < listaSkills.Count; i++)
{
GameObject listItem = Instantiate(SkillPrefab) as GameObject;
listItem.GetComponent<SkillManager>().skill = listaSkills[i];
//listItem.transform.SetParent(SkillsContent.transform, false);
listItem.transform.parent = SkillsContent.transform;
}
When I run this, no item is seen in the ScrollView, but I can see the SkillItem added to the hierarchy:
If I move to Scene tab after playing, I see a square with red lines crossing it:
Why is my item not displaying? Why the red cross? How can I populate my ScrollView?
EDIT:
This is the code of SkillManager, the script added to SkillPrefab:
public class SkillManager : MonoBehaviour
{
public TMP_InputField toSpend;
public TMP_InputField rangos;
public TMP_InputField modificadores;
public TMP_InputField total;
public Button plusButton;
public Button minusButton;
public TMP_Text nombre;
public Skill skill;
private int modificador;
private int pointsToSpend;
private int totalPoints;
// Start is called before the first frame update
void Start()
{
print("Start");
if(total!=null)
total.text = "0";
if(modificadores!=null)
modificadores.text = "0";
if (toSpend != null)
{
toSpend.GetComponent<TMP_InputField>().text = GetSkillPoints();
totalPoints = int.Parse(total.GetComponent<TMP_InputField>().text);
pointsToSpend = int.Parse(toSpend.GetComponent<TMP_InputField>().text);
}
else
{
GameObject GameObjectToSpend = GameObject.FindGameObjectWithTag("tospend");
toSpend = GameObjectToSpend.GetComponent<TMP_InputField>();
if (toSpend == null)
{
print("Sigue siendo nulo");
}
else
{
toSpend.text= GetSkillPoints();
//totalPoints = int.Parse(total.GetComponent<TMP_InputField>().text);
if(total!=null)
totalPoints = int.Parse(total.text);
if(toSpend!=null)
pointsToSpend = int.Parse(toSpend.text);
}
}
if (skill != null)
{
modificador = GetModificador(skill);
string sModificador = modificadores.GetComponent<TMP_InputField>().text;
int iModificador = int.Parse(sModificador);
modificadores.GetComponent<TMP_InputField>().text = iModificador.ToString();
}
if (plusButton != null)
{
plusButton.onClick.AddListener(PlusButtonClicked);
minusButton.onClick.AddListener(MinusButtonClicked);
}
}
private string GetSkillPoints()
{
return "1";
}
public void MinusButtonClicked()
{
string ranks = rangos.GetComponent<TMP_InputField>().text;
int ranksInt = int.Parse(ranks);
if (ranksInt > 0)
{
int newRank = ranksInt - 1;
pointsToSpend += 1;
rangos.GetComponent<TMP_InputField>().text = newRank.ToString();
toSpend.GetComponent<TMP_InputField>().text = pointsToSpend.ToString();
total.GetComponent<TMP_InputField>().text = (newRank + modificador).ToString();
skill.Puntos = newRank;
}
}
public void PlusButtonClicked()
{
string ranks=rangos.GetComponent<TMP_InputField>().text;
int ranksInt = int.Parse(ranks);
Character character = Almacen.instance.Character;
int level = character.CharacterLevel;
if (ranksInt < level && pointsToSpend > 0)
{
int newRank = ranksInt + 1;
rangos.GetComponent<TMP_InputField>().text = newRank.ToString();
pointsToSpend -= 1;
toSpend.GetComponent<TMP_InputField>().text = pointsToSpend.ToString();
total.GetComponent<TMP_InputField>().text = (newRank + modificador).ToString();
skill.Puntos = newRank;
}
}
private int GetModificador(Skill skill)
{
int retorno=0;
if (skill.Clasea)
{
retorno += 3;
}
else
{
retorno += 0;
}
retorno += GetModificadorCaracteristica();
return retorno;
}
private int GetModificadorCaracteristica()
{
Utils utils = new Utils();
int retorno = 0;
int characteristic=0;
switch (skill.Caracteristica)
{
case "Fue":
characteristic = Almacen.instance.Character.EffectiveStr;
break;
case "Des":
characteristic = Almacen.instance.Character.EffectiveDex;
break;
case "Con":
characteristic = Almacen.instance.Character.EffectiveCon;
break;
case "Int":
characteristic = Almacen.instance.Character.EffectiveInt;
break;
case "Sab":
characteristic = Almacen.instance.Character.EffectiveWis;
break;
case "Car":
characteristic = Almacen.instance.Character.EffectiveCha;
break;
}
retorno = utils.GetCharModifier(characteristic);
return retorno;
}
}
it looks like you instantiate the object as a GameObject. but this will not be seen in the canvas because it isn't a UI component. you may want to add a sprite or image to the component and instantiate that into the Canvas. it will look something like this:
public class SkillPrefab
{
//put all your variables here!!!
public Sprite skillSprite;
}
public class YourClassName : MonoBehaviour
{
[SerializeField]
public List<SkillPrefab> skills = new List<SkillPrefab>();
private void Update()
{
Sprite listItem = Instantiate(skills[0].skillSprite); //the index is the skill you want to spawn in the list.
}
}
this does take into account that you have made your skills into a list of skills that you can acces.

C# Instances share same values

programming student here, quite new to what i am about to ask but i'm sure you people will know. I have to make a game where several pictureboxes are created using an array. I also have to make a class that has a health variable of 5. When you click on one of the pictureboxes, its health has to go down by 1. I am as far as this, but the problem is that the health variable is shared by all pictureboxes, where in reality I want every picturebox to have it's own health.
This is my code:
public partial class Form1 : Form
{
Invader monster; // Invader is the name of the class
Random rand = new Random();
PictureBox[] pb = new PictureBox[5];
private void Spawner()
{
for (int i = 0; i < 5; i++)
{
this.monster = new Invader();
this.pb[i] = new PictureBox();
this.pb[i].Name = "pb" + i.ToString();
this.pb[i].Location = new Point(rand.Next(10, 300), monster.LocY);
this.pb[i].BackgroundImageLayout = ImageLayout.Stretch;
this.pb[i].BackgroundImage = Image.FromFile(#"Path");
this.pb[i].BackColor = Color.Transparent;
this.pb[i].Size = new System.Drawing.Size(40, 30);
this.Controls.Add(this.pb[i]);
this.pb[i].Click += this.Form1_Click;
}
}
private void Form1_Click(object sender, EventArgs e)
{
PictureBox currentpicturebox = (PictureBox)sender;
this.monster.HealthDown();
if (this.monster.Health == 0)
{
currentpicturebox.Dispose();
}
}
and my class:
class Invader
{
// Fields
private int health;
// Properties
public int Health
{
get { return this.health; }
}
// Constructor
public Invader()
{
this.health = 5;
}
// Methods
public void HealthDown()
{
this.health -= 1;
}
Lets say i click 1 picture box 4 times, and click another one 1 time. With this code the picturebox last clicked on will be disposed. Any ideas on how to fix this?
Your Invader monster is an instance variable of Form1 and in your method Spawner() inside the for loop you are reassigning it again every time: this.monster = new Invader();
Basically when you click on a picturebox (isn't different what) in your Form1_Click method happen that is everytime your last monster istance that get it's health down and not the supposed one.
In order to fix this you can:
transform monster in an array of Invader object instead of an Invader object, the number of elements must be the same as the number of pictureboxes
foreach picturebox assign as a Tag the index of the corrispondent Invader on the monster array
Here an example:
public partial class Form1 : Form
{
// EDIT - Become an array
Invader[] monster = new Invader[5]; // Invader is the name of the class
Random rand = new Random();
PictureBox[] pb = new PictureBox[5];
private void Spawner()
{
for (int i = 0; i < 5; i++)
{
this.monster[i] = new Invader(); // EDIT
this.pb[i] = new PictureBox();
this.pb[i].Name = "pb" + i.ToString();
this.pb[i].Location = new Point(rand.Next(10, 300), monster.LocY);
this.pb[i].BackgroundImageLayout = ImageLayout.Stretch;
this.pb[i].BackgroundImage = Image.FromFile(#"Path");
this.pb[i].BackColor = Color.Transparent;
this.pb[i].Size = new System.Drawing.Size(40, 30);
this.Controls.Add(this.pb[i]);
this.pb[i].Click += this.Form1_Click;
this.pb[i].Tag = i; // EDIT - Added tag assignation
}
}
private void Form1_Click(object sender, EventArgs e)
{
PictureBox currentpicturebox = (PictureBox)sender;
this.monster[(int)currentpicturebox.Tag].HealthDown(); // EDIT
if (this.monster[(int)currentpicturebox.Tag].Health == 0) //EDIT
{
currentpicturebox.Dispose();
}
}

Unity GUI combo box with search

I need a list which is a lot of list (enum list). And right now the list is using the pop up (combo box), but the normal combo box is not really help because too many item inside it. It kind of frustrating when try to select item that is far away at bottom. The list are full on the screen when openned.
When openning a combo box and type a letter it will jump only the first letter, when I press second letter the list will be jump to another first letter start. So example, I want to select DIAMOND -> I press D and it will go to the list with D start. And when I press I, it will jump to item that start with I instead of DI.
Is there any component of GUI to have the search?
Unity haven't components for search like your.
But you can try something like this (SearchEnumLabel function):
using System;
using System.Globalization;
using System.Linq;
using UnityEditor;
public enum States
{
ABCDEF,
ACBDEF,
AdEXG,
bErDSa
}
[CustomEditor(typeof(ObjectControllerTester))]
[CanEditMultipleObjects]
public class ObjectControllerTesterEditor : Editor
{
States _selected;
public override void OnInspectorGUI ()
{
_selected = SearchEnumLabel("My search enum", _selected);
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField("[Debug]Current selected: "+_selected);
}
private String _searchEnumText = "";
private bool _isSearchEnumLabelInSearch = false;
private T SearchEnumLabel<T>(String label, T state) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
EditorGUILayout.LabelField("T must be an enumerated type");
return state;
}
var states = Enum.GetValues(typeof (T)).Cast<object>().Select(o => o.ToString()).ToArray();
if (string.IsNullOrEmpty(_searchEnumText) && states.Length > 0) _searchEnumText = state.ToString(CultureInfo.InvariantCulture);
var text = EditorGUILayout.TextField(label, _searchEnumText);
if (text != _searchEnumText || _isSearchEnumLabelInSearch)
{
_searchEnumText = text;
var mach = states.Select((v,i)=>new {value = v, index = i}).FirstOrDefault(a => a.value.ToLower().StartsWith(text.ToLower()));
var targetState = state;
if (mach != null) targetState = (T) Enum.GetValues(typeof (T)).GetValue(mach.index);
EditorGUILayout.LabelField("Select closest: "+targetState);
Repaint();
state = targetState;
_isSearchEnumLabelInSearch = !string.Equals(_searchEnumText, targetState.ToString(CultureInfo.InvariantCulture), StringComparison.CurrentCultureIgnoreCase);
}
return state;
}
}
This script will show something like this:
Default view
After input some data
=== UPDATE ===
More complex variant with fast select buttons
using System;
using System.Globalization;
using System.Linq;
using UnityEditor;
using UnityEngine;
public enum States
{
ABCDEF,
ACBDEF,
AdEXG,
bErDSa,
sEOjsfl,
SdDiaso,
POsdjaow,
PSADJsd,
Oasdo,
IOQWEnds
}
[CustomEditor(typeof(ObjectControllerTester))]
[CanEditMultipleObjects]
public class ObjectControllerTesterEditor : Editor
{
States _selected;
public override void OnInspectorGUI()
{
_selected = SearchEnumLabel("My search enum", _selected);
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField("[Debug]Current selected: " + _selected);
}
private String _searchEnumText = "";
private bool _isSearchEnumLabelInSearch = false;
private T SearchEnumLabel<T>(String label, T state) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
EditorGUILayout.LabelField("T must be an enumerated type");
return state;
}
var states = Enum.GetValues(typeof(T)).Cast<object>().Select(o => o.ToString()).ToArray();
if (string.IsNullOrEmpty(_searchEnumText) && states.Length > 0) _searchEnumText = state.ToString(CultureInfo.InvariantCulture);
var text = EditorGUILayout.TextField(label, _searchEnumText);
if (text != _searchEnumText || _isSearchEnumLabelInSearch)
{
_searchEnumText = text;
var mach = states.Select((v, i) => new { value = v, index = i }).Where(a => a.value.ToLower().StartsWith(text.ToLower())).ToList();
var targetState = state;
if (mach.Any())
{
// many of results
targetState = (T)Enum.GetValues(typeof(T)).GetValue(mach[0].index);
EditorGUILayout.LabelField("Select closested: " + targetState);
Repaint();
var selected = GUILayout.SelectionGrid(-1, mach.Select(v => v.value).ToArray(), 4);
if (selected != -1)
{
targetState = (T)Enum.GetValues(typeof(T)).GetValue(mach[selected].index);
_searchEnumText = targetState.ToString(CultureInfo.InvariantCulture);
_isSearchEnumLabelInSearch = false;
GUI.FocusControl("FocusAway");
Repaint();
}
}
state = targetState;
_isSearchEnumLabelInSearch = !string.Equals(_searchEnumText, targetState.ToString(CultureInfo.InvariantCulture), StringComparison.CurrentCultureIgnoreCase);
}
return state;
}
}
Tap button to select target enum
Here is my solution, you can replace 'EnumNBEvent' as you like.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Newborn.Pb.Event;
using System;
using System.Reflection;
using Google.Protobuf.Reflection;
using System.Text.RegularExpressions;
[CustomPropertyDrawer(typeof(EnumNBEvent), false)]
public class FSMEventDrawer : PropertyDrawer {
struct EnumStringValuePair : IComparable<EnumStringValuePair>
{
public string strValue;
public int intValue;
public int CompareTo(EnumStringValuePair another)
{
if (intValue < another.intValue)
return -1;
else if (intValue > another.intValue)
return 1;
return 0;
}
}
Dictionary<int, string> filters = new Dictionary<int, string>();
//string filter = string.Empty;
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
int y = (int)position.position.y;
if (!filters.ContainsKey(y))
filters[y] = string.Empty;
EditorGUI.BeginProperty(position, label, property);
EditorGUI.LabelField(new Rect(position.x, position.y, 100, 20), property.name);
filters[y] = EditorGUI.TextField(new Rect(position.x + 100, position.y, 60, 15), filters[y]);
List<EnumStringValuePair> enumList = GetEnumList(filters[y]);
List<string> enumStrList = new List<string>(enumList.Count);
for (int i = 0; i < enumList.Count; ++i)
{
enumStrList.Add(enumList[i].strValue);
}
int selectedIndex = 0;
for (int i = 0; i < enumList.Count; ++i)
{
if (enumList[i].intValue == property.enumValueIndex)
{
selectedIndex = i;
break;
}
}
selectedIndex = EditorGUI.Popup(new Rect(position.x + 170, position.y, 200, 20), selectedIndex, enumStrList.ToArray());
if (enumList.Count > selectedIndex)
{
property.enumValueIndex = enumList[selectedIndex].intValue;
}
EditorGUI.EndProperty();
}
private List<EnumStringValuePair> GetEnumList(string filter)
{
List<EnumStringValuePair> allList = new List<EnumStringValuePair>();
Array enumValues = Enum.GetValues(typeof(EnumNBEvent));
for (int i = 0; i < enumValues.Length; ++i)
{
EnumStringValuePair pair = new EnumStringValuePair();
pair.strValue = enumValues.GetValue(i).ToString();
pair.intValue = (int)enumValues.GetValue(i);
allList.Add(pair);
}
List<EnumStringValuePair> ret = new List<EnumStringValuePair>();
Regex regex = new Regex(filter.ToLower());
for (int i = 0; i < allList.Count; ++i)
{
if (regex.IsMatch(allList[i].strValue.ToLower()))
{
ret.Add(allList[i]);
}
}
return ret;
}
}

Blackberry how to design the Screen like grid view

I am very new to blackberry development and i don't even know how to start. I already read some part of it from it's official site
http://developer.blackberry.com/devzone/files/design/bb7/UI_Guidelines_BlackBerry_Smartphones_7_1.pdf
and other so many link, but i can not post all the link as it is saying thay if you want to post more links then you must have 10 reputation and i dont have that so sorry for that,
Now my question is i want to design layout like this http://postimg.org/image/we3leycsd/
How can i design exactly this kind of layout. I am using eclipse for Blackberry development.
Please help i already tried many things but i am not able to achieve this.
Your any kind of help would be appreciated. Thank you in advance.
I'd create a custom HorizontalFieldManager with n VerticalFieldManagers inside, then override the add and delete methods. Here is something I made before, that should work for you, it adds the new fields to the shortest column.
StaggeredListView.java:
public class StaggeredListView extends HorizontalFieldManager
{
private int column_spacing = 0;
public StaggeredListView(int columns)
{
super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR | USE_ALL_WIDTH);
if (columns < 1)
{
throw new RuntimeException("Number of columns needs to be larger than 0.");
}
final int width = Display.getWidth() / columns;
for (int i = 0; i < columns; i++)
{
VerticalFieldManager vfm = new VerticalFieldManager(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR)
{
protected void sublayout(int maxWidth, int maxHeight)
{
maxWidth = Math.min(width, getPreferredWidth());
maxHeight = Math.min(maxHeight, getPreferredHeight());
super.sublayout(width, maxHeight);
super.setExtent(width, maxHeight);
}
};
super.add(vfm);
}
}
public int getColumnCount()
{
return getFieldCount();
}
/**
* Sets the spacing between columns.
*
* <p>
* Spacing between fields is <i><b>not</b></i> set.
* </p>
*/
public void setColumnSpacing(int spacing)
{
if (spacing < 0) throw new RuntimeException("Column spacing my not be negative.");
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
((VerticalFieldManager) getField(i)).setPadding(0, 0, 0, spacing);
}
column_spacing = spacing;
}
/**
* Get the value currently assigned via the {#link #setColumnSpacing(int)} method.
*
* #return
*/
public int getColumnSpacing()
{
return column_spacing;
}
/**
* Deletes all fields from each of the columns.
*/
public void clear()
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
((VerticalFieldManager) getField(i)).deleteAll();
}
}
/**
* Delete specified field from the columns.
*
* <p>
* Does <b><i>not</i></b> rearrange fields.
* </p>
*/
public void delete(Field field)
{
int length = getColumnCount();
for (int i = 0; i < length; i++)
{
try
{
((VerticalFieldManager) getField(i)).delete(field);
break;
} catch (IllegalArgumentException e)
{
// field not in this manager
}
}
}
/**
* Adds the field to the column with the least height.
*/
public void add(Field field)
{
// find the vfm with least height
int index = 0;
int height = ((VerticalFieldManager) getField(index)).getPreferredHeight();
int length = getColumnCount();
for (int i = 1; i < length; i++)
{
int temp_height = ((VerticalFieldManager) getField(i)).getPreferredHeight();
if (temp_height < height)
{
height = temp_height;
index = i;
}
}
((VerticalFieldManager) getField(index)).add(field);
}
}
As for the item's contained in it, I'd create a field with an image and text, then paint it myself (I've had a lot of issues with focus and find it easier just to use paint).
You can use this to make a BaseButton http://developer.blackberry.com/bbos/java/documentation/tutorial_create_custom_button_1969896_11.html
BaseButton.java:
public abstract class BaseButton extends Field
{
// flags to indicate the current visual state
protected boolean _visible = true;
protected boolean _active;
protected boolean _focus;
protected boolean drawfocus = false;
private int touch_top = 0;
private int touch_right = 0;
private int touch_bottom = 0;
private int touch_left = 0;
protected boolean fire_on_click = true; // false fires on unclick
public BaseButton()
{
this(0);
}
public BaseButton(long style)
{
super((style & Field.NON_FOCUSABLE) == Field.NON_FOCUSABLE ? style : style | Field.FOCUSABLE);
}
/**
* Sets the radius around the button to trigger touch events.
* <p>
* (0,0,0,0) by default.
* </p>
*/
public void setTouchRadius(int top, int right, int bottom, int left)
{
touch_top = top;
touch_right = right;
touch_bottom = bottom;
touch_left = left;
}
protected void onFocus(int direction)
{
_focus = true;
invalidate();
super.onFocus(direction);
}
protected void onUnfocus()
{
if (_active || _focus)
{
_focus = false;
_active = false;
invalidate();
}
super.onUnfocus();
}
public void set_visible(boolean visible)
{
_visible = visible;
invalidate();
}
public boolean is_visible()
{
return _visible;
}
protected void drawFocus(Graphics g, boolean on)
{
if (drawfocus) super.drawFocus(g, on);
}
protected void layout(int width, int height)
{
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
protected boolean keyUp(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = false;
invalidate();
return true;
}
return false;
}
protected boolean keyDown(int keycode, int time)
{
if (Keypad.map(Keypad.key(keycode), Keypad.status(keycode)) == Characters.ENTER)
{
_active = true;
invalidate();
}
return super.keyDown(keycode, time);
}
protected boolean keyChar(char character, int status, int time)
{
if (character == Characters.ENTER)
{
clickButton();
return true;
}
return super.keyChar(character, status, time);
}
protected boolean navigationClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelClick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = true;
invalidate();
if (fire_on_click) clickButton();
}
return true;
}
protected boolean navigationUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean trackwheelUnclick(int status, int time)
{
if (status != 0)
{ // non-touch event
_active = false;
invalidate();
if (!fire_on_click) clickButton();
}
return true;
}
protected boolean invokeAction(int action)
{
switch (action)
{
case ACTION_INVOKE :
{
clickButton();
return true;
}
}
return super.invokeAction(action);
}
protected boolean touchEvent(TouchEvent message)
{
boolean isOutOfBounds = touchEventOutOfBounds(message);
switch (message.getEvent())
{
case TouchEvent.CLICK :
if (!_active)
{
_active = true;
invalidate();
}
if (!isOutOfBounds)
{
if (fire_on_click) clickButton();
return true;
}
case TouchEvent.DOWN :
if (!isOutOfBounds)
{
if (!_active)
{
_active = true;
invalidate();
}
return true;
}
return false;
case TouchEvent.UNCLICK :
if (_active)
{
_active = false;
invalidate();
}
if (!isOutOfBounds)
{
if (!fire_on_click) clickButton();
return true;
}
case TouchEvent.UP :
if (_active)
{
_active = false;
invalidate();
}
default :
return false;
}
}
private boolean touchEventOutOfBounds(TouchEvent message)
{
int x = message.getX(1);
int y = message.getY(1);
return (x < 0 - touch_left || y < 0 - touch_top || x > getWidth() + touch_right || y > getHeight() + touch_bottom);
}
public void setDirty(boolean dirty)
{
}
public void setMuddy(boolean muddy)
{
}
public void clickButton()
{
if (_visible) fieldChangeNotify(0);
}
}
ImageSubtitleButton.java:
public class ImageSubtitleButton extends BaseButton
{
private static final int FOCUS_THINKNESS = 2;
String title;
Bitmap image_default;
int height;
public ImageSubtitleButton(String title, String image_default)
{
this.image_default = Bitmap.getBitmapResource(image_default);
setTitle(title);
}
public void setTitle(String title)
{
this.title = title;
height = image_default.getHeight() + getFont().getHeight() + (FOCUS_THINKNESS * 2);
updateLayout();
invalidate();
}
public int getPreferredWidth()
{
return Math.max(getFont().getAdvance(title), image_default.getWidth());
}
public int getPreferredHeight()
{
return height;
}
protected void paint(Graphics graphics)
{
int x = (getWidth() - image_default.getWidth()) / 2;
int y = 0;
graphics.drawBitmap(x, y, image_default.getWidth(), image_default.getHeight(), image_default, 0, 0);
if (_focus)
{
graphics.setColor(Color.BLUE); // your focus colour
for (int i = 0; i < FOCUS_THINKNESS; i++)
{
graphics.drawRect(x + i, y + i, image_default.getWidth() - (i * 2), image_default.getHeight() - (i * 2));
}
}
graphics.setColor(Color.BLACK);
y = image_default.getHeight();
graphics.drawText(title, x, y);
}
}
Now you can add these to your screen as follows:
StaggedListView listview = new StaggedListView(2);
ImageSubtitleButton button = new ImageSubtitleButton("test", "test.png");
listview.add(button);
add(listview);
You'll need to set the preferred width and height of the ImageSubtitleButton to keep it uniform, as in the example image you posted.
Apologies, I don't have time to create a full answer, but I personally would not use the HFM/VFM combination to do this. Instead use one Manager that provides the Grid. If you are using a late enough level OS you have GridFieldManager that does this,
GridFieldManager
but I have had mixed experiences with that Manager. So I generally use this Manager:
TableLayoutManager
I hope this gets you going.