Dropdown list for country and city:
I want to make a spinner in android just like this attached image. For example, you select the list and you can choose any city from the country.Only the cities should be clickable and can be stored from the list. The country name should not be clickable.Having problem in disabling some of the items from the spinner.
This is the xml for the spinner.
`<Spinner
android:id="#+id/districtSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:hint="District"
android:textSize="16sp"
android:theme="#style/MyEditText"
/>`
And this is the code:
`Spinner DistrictBetterSpinner;
String[] District_Spinner = new String[]{"Punjab", "Rawalpindi", "Attock", "Faisalabad", "Chakwal", "Bhakkar", "Jhelum", "Multan", "Chiniot"
, "Bhawalpur", "Jhelum", "Gujrat", "Gujranwala", "Lahore", "Mianwali", "Khyber Pakhtunkhwa (KPK)", "Abbotabad", "Haripur", "Kohat",
"Sindh", "Hyderabad", "Jacobabad", "Balochistan", "Awaran", "Gawadar", "Federally Administered Tribal Areas", "Khyber Agency",
"Mohmat Agency", "Azad Jammu and Kashmir", "Neelum", "Bagh", "Gilgit Baltistan", "Skardu", "Astore"};
List<String> spinnerlist;
ArrayAdapter<String> arrayadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_post);
DistrictBetterSpinner = (Spinner) findViewById(R.id.districtSpinner);
spinnerlist = new ArrayList<>(Arrays.asList(District_Spinner));
arrayadapter = new ArrayAdapter<String>(AddPostActivity.this, R.layout.spinner_item, spinnerlist);
public boolean isEnabled(int position){
if (position == 0 || position==1) {
return false;
} else {
return true;
}
}
#Override
public View getDropDownView ( int position, View convertView, ViewGroup parent){
View view = super.getDropDownView(position, convertView, parent);
TextView spinnerTextView = (TextView) view;
if (position == 0) {
// Set the disable item text color
spinnerTextView.setTextColor(Color.BLACK);
} else {
spinnerTextView.setTextColor(Color.GRAY);
}
return view;
}
}
;
arrayadapter.setDropDownViewResource(R.layout.spinner_item);
DistrictBetterSpinner.setAdapter( arrayadapter);
`
I think the following may be what you are after (new lines added to getDropDownView after you set the TextColor for Cities to grey):-
#Override
public View getDropDownView ( int position, View convertView, ViewGroup parent){
View view = super.getDropDownView(position, convertView, parent);
TextView spinnerTextView = (TextView) view;
if (position == 0) {
// Set the disable item text color
spinnerTextView.setTextColor(Color.BLACK);
} else {
spinnerTextView.setTextColor(Color.GRAY);
spinnerTextView.setOnclickListener( new View.OnClickListener() {
#Override
public void onClick(View view) {
//YOUR ONCLICK HANDLING CODE HERE
}
});
}
return view;
}
P.S. in my comment above I mentioned getView as an alternative. It isn't as that's the selection view rather than the dropdown (got mixed up with ListViews).
Looking more closely at your Answer and Code. I see that you haven't got anywhere really. So here's a rudimentary example based upon your code.
First a new layout file for an entry in the dropdown list (I've also cheated a little and used this for the selected entry, you probably have a separate layout for each). This is spinner_item.xml :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/spinnerTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
As you want customised features you should probably have a custom adapter (which is what you appeared to be attemtping in your code). The adapter handles placing the data (arrayList in your case) into the views used by the spinner (the term used is inflate). So here's the custom adapter which I've placed into it's own file. This is MyArrayAdapter.java :-
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Mike092015 on 31/10/2016.
*/
public class MyArrayAdapter extends ArrayAdapter<String> {
private Context context;
private TextView district;
private ArrayList<String> districts;
public MyArrayAdapter(Activity context, int layout, ArrayList<String> districts) {
super(context, layout, districts);
this.context = context;
this.districts = districts;
}
#Override
public View getDropDownView(int position, View convertview, ViewGroup parent) {
View v = convertview;
if (v == null) {
v = LayoutInflater.from(this.context).inflate(R.layout.spinner_item,parent,false);
}
district = (TextView) v.findViewById(R.id.spinnerTextView);
district.setText(districts.get(position));
district.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context,"You clicked me",Toast.LENGTH_SHORT).show();
}
});
return v;
}
public View getView(int position, View convertview, ViewGroup parent) {
View v = convertview;
if (v == null) {
v = LayoutInflater.from(this.context).inflate(R.layout.spinner_item,parent,false);
}
district = (TextView) v.findViewById(R.id.spinnerTextView);
district.setText(districts.get(position));
return v;
}
}
Note the onClickListener in the getDropDownView this is where you catch and handle the clicking of an entry (in this case it just issues a toast).
activity_main.xml (the layout that includes the spinner, little, if any different from your layout) is :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Testing"/>
<Spinner
android:id="#+id/districtSpinner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:hint="District"
android:textSize="16sp"
/>
</LinearLayout>
Lastly the activity, to test this I've used MainActivity, so MainActicity.java is:-
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Spinner;
import java.util.ArrayList;
import java.util.Arrays;
/**
* Created by Mike092015 on 3/06/2016.
*/
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Spinner DistrictBetterSpinner;
String[] District_Spinner = new String[]{"Punjab", "Rawalpindi", "Attock", "Faisalabad", "Chakwal", "Bhakkar", "Jhelum", "Multan", "Chiniot"
, "Bhawalpur", "Jhelum", "Gujrat", "Gujranwala", "Lahore", "Mianwali", "Khyber Pakhtunkhwa (KPK)", "Abbotabad", "Haripur", "Kohat",
"Sindh", "Hyderabad", "Jacobabad", "Balochistan", "Awaran", "Gawadar", "Federally Administered Tribal Areas", "Khyber Agency",
"Mohmat Agency", "Azad Jammu and Kashmir", "Neelum", "Bagh", "Gilgit Baltistan", "Skardu", "Astore"};
ArrayList<String> spinnerlist;
MyArrayAdapter arrayadapter;
DistrictBetterSpinner = (Spinner) findViewById(R.id.districtSpinner);
spinnerlist = new ArrayList<>(Arrays.asList(District_Spinner));
arrayadapter = new MyArrayAdapter(this,R.layout.spinner_item,spinnerlist);
arrayadapter.setDropDownViewResource(R.layout.spinner_item);
DistrictBetterSpinner.setAdapter(arrayadapter);
}
}
Note there are some changes but it is very much based upon your code.
Related
Background
Out automatic tests use views' ids to be able to click on them, so we add ids whenever possible.
The problem
For popup menus, sometimes it's needed to populate them dynamically, but as I've found, even when I do add id for each item, the id isn't found, and can't be used. Even using DDMS's feature "dump view hierarchy for UI automator" shows that no view in the popup menu has an id.
What I've tried
This is a sample code of what I use, to try to set an id for the a single menu item.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View v=findViewById(R.id.button);
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
PopupMenu popupMenu = new PopupMenu(MainActivity.this, v);
final Menu menu = popupMenu.getMenu();
menu.add(0, R.id.myMenuItem, 0, R.string.app_name).setOnMenuItemClickListener(new OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(final MenuItem item) {
return false;
}
}) ;
popupMenu.show();
}
});
}
Note that the id is declared in "ids.xml" file, as such:
<item name="myMenuItem" type="id"/>
And this is what DDMS tool shows me :
The question
How come this code doesn't work as expected (meaning have an id for the menu item view) ? What can I do to make the views in it to have ids? What is the correct way to add ids for menu items that are created dynamically ?
Alright, this is by no means an answer to the problem described in the question. Look at it as an alternative to replace PopupMenu in order to achieve what was asked.
No PopupMenu
After digging through the documents for PopupMenu and its source code, I finally come to understand that PopupMenu is not an implementation that would allow customization (my apology to the PO for the misconception in the comments).
An alternative
As an alternative, a ListPopupWindow is a preferred choice to create a popup menu with the following reasons:
It shares the same parent with PopupMenu - ListView.
It is flexible, allowing custom Adapter to be defined with custom layout.
It also allows run-time creation like PopupMenu does, and allows attaching resource id to the item view.
Implementation
First of all, let's define a custom layout for the popup item (popup_item_view.xml).
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="#+id/popup_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Next, define a custom Adapter class to manipulate the layout.
package com.example.popupmenu;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PopupAdapter extends BaseAdapter {
public static class Item {
public final int id;
public final String title;
public Item(int id, #NonNull String title) {
this.id = id;
this.title = title;
}
}
private List<Item> mItemList = new ArrayList<>();
public PopupAdapter(#NonNull Item[] items) {
mItemList.addAll(Arrays.asList(items));
}
#Override
public int getCount() {
return mItemList.size();
}
#Override
public Item getItem(int position) {
return mItemList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final Item item = getItem(position);
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.popup_item_view, parent, false);
}
convertView.setId(item.id);
TextView titleView = (TextView) convertView.findViewById(R.id.popup_text);
titleView.setText(item.title);
return convertView;
}
}
Finally, replace the PopupMenu code with this.
PopupAdapter.Item[] items = {
new PopupAdapter.Item(R.id.popup_item_1, "item 1"),
new PopupAdapter.Item(R.id.popup_item_2, "item 2")
};
ListPopupWindow popup = new ListPopupWindow(MainActivity.this);
popup.setAnchorView(view);
popup.setAdapter(new PopupAdapter(items));
popup.setModal(true);
popup.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// do something
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
// do something
}
});
popup.show();
Hope this helps.
i try to make a list with Clickable strings from my string array.
By clicking on any String i want to get to a classes named after this string.
I tried with onListItemClick... but it doesnt work :S .. any suggestions for a solution?
Thank you for your time :)
I've got some Strings for example called "Title 1", "Title 2" and a little description under every title called "Description 1", "Description 2"... in a ListView. By clicking on "title" i want to get to a class named Title . How to do that with my construct?
Listview
Title 1
Description 1
Title 2
Description 2
Title 3
Description 3
ListviewEnd
package com.example.benice;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class Main extends Activity implements OnClickListener {
String[] titles; // String Array
String[] beschreibung; // String Array
ListView list;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Automatisch generierter Methodenstub
super.onCreate(savedInstanceState);
setContentView(R.layout.listview);
Resources res = getResources();
titles = res.getStringArray(R.array.titles);
beschreibung = res.getStringArray(R.array.beschreibung);
list = (ListView) findViewById(R.id.listView1);
VivzAdapter adapter = new VivzAdapter(this, titles, beschreibung);
list.setAdapter(adapter);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Automatisch generierter Methodenstub
onListItemClick(l, v, position, id);
String cheese = titles[position];
try {
Class ourClass = Class.forName("com.example.benice." + cheese);
Intent ourIntent = new Intent(Main.this, ourClass);
startActivity(ourIntent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
#Override
public void onClick(View v) {
// TODO Automatisch generierter Methodenstub
}
}
class VivzAdapter extends ArrayAdapter<String> {
Context context;
String[] titlesArray;
String[] beschreibungArray;
VivzAdapter(Context c, String[] titles, String[] beschreibung) {
super(c, R.layout.single_row, R.id.titleTextView, titles);
this.context = c;
this.titlesArray = titles;
this.beschreibungArray = beschreibung;
}
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflator = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflator.inflate(R.layout.single_row, parent, false);
TextView titles = (TextView) row.findViewById(R.id.titleTextView);
TextView beschreibung = (TextView) row.findViewById(R.id.beschTextView);
titles.setText(titlesArray[position]);
beschreibung.setText(beschreibungArray[position]);
return row;
}
}
this is how the .xml looks like
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="90dp"
android:background="#drawable/backgg"
android:orientation="vertical" >
<TextView
android:id="#+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="5dp"
android:text="Here is the Title"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#fefefe" />
<TextView
android:id="#+id/beschTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="Here is the Descrition"
android:textColor="#fefefe" />
</LinearLayout>
It's possible to construct your ListView by extending ListActivity rather than Activity - onListItemClick will only work as it is used in you code if you extend ListActivity. You can also unimplement OnClickListener regardless of what you do. For instance:
public class MainActivity extends ListActivity {
String[] titles = { "One", "two", "three", "four", "five"};
String[] beschreibung = { "1", "2", "3", "4", "5"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// VivzAdapter? Good to see another SlideNerd fan :)
VivzAdapter adapter = new VivzAdapter(this, titles, beschreibung);
setListAdapter(adapter);
}
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
String cheese = titles[position];
try {
Class ourClass = Class.forName("com.example.benice." + cheese);
Intent ourIntent = new Intent(this, ourClass);
startActivity(ourIntent);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
This will work for as long as you have other Classes called "One", "two", "three" etc. You also need to alter the construction of your getView() method in the custom ArrayAdapter.
public View getView(int position, View convertView, ViewGroup parent) {
View row;
if (convertView == null) {
LayoutInflater inflator = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflator.inflate(R.layout.row, parent, false);
} else {
row = convertView;
}
TextView titles = (TextView) row.findViewById(R.id.titleTextView);
TextView beschreibung = (TextView) row.findViewById(R.id.beschTextView);
titles.setText(titlesArray[position]);
beschreibung.setText(beschreibungArray[position]);
return row;
}
This post goes into more depth on onListItemClick.
First of all you need to implement an AdapterView.OnItemClickListener not View.OnClickListener as you Activity is doing.
Then you need to also set this listener on your listview, like this for example:
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// your code here
}
});
There might be other things wrong with your code, for example, Class.forName() is most likely going to throw exceptions if you're feeding it random strings from a list view, but without more detail about what exactly you're trying to do that's hard to say.
There's a few issues with your code, and i got a few tips for you as well.
The first issue, as to why ListClick event doesn't work. You never actually bind it to the listview.
To enable click events on your list, use this code:
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Put your code here
}
});
Also, you have implemented onClick in your activity, because you have 'implements OnClickListener'. Why? You dont use it, so just remove it.
I'm fairly certain this could also play a role in how click events are handled by your list click event handler. As the click event for the activity might get triggered first, and then stop the click event of the list from firing.
A few tips:
1) Write all your code in english, even variable names and comments. Makes is much easier for people to read (especially since you're asking for help on an english speaking forum)
2) You can use 'LayoutInflater.from(Context)' to get a LayoutInflater, instead of that long line of code where you use 'getSystemService'.
I am populating a ListView with a Base Adapter in such a way that all except the last item will be checkboxes and the last item will be a TextView with a button.
Here are the XML files.
Final Item:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="#+id/tv_newitem"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="3"
android:text="#string/new_account_text"
/>
<Button
android:id="#+id/b_newitem"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="2"
android:text="#string/add_button_text"
android:onClick="showNewAccountDialog"
/>
</LinearLayout>
Checkboxes:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
>
<CheckBox
android:focusable="true"
android:id="#+id/account_item_cb"
android:layout_height="wrap_content"
android:layout_width="match_parent"
></CheckBox>
</LinearLayout>
Here is the Class file for the base adapter:
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
public class AccountListAdapter extends BaseAdapter{
private static final int TYPE_ACCOUNT = 0;
private static final int TYPE_NEW_ACCOUNT = 1;
private static final int TYPE_MAX_COUNT = 2;
private LayoutInflater mInflator;
private ArrayList<String> mStrings;
private ArrayList<String> mSelectedStrings;
public AccountListAdapter(Context context, ArrayList<String> array)
{
mInflator = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mStrings = array;
mSelectedStrings = new ArrayList<String>();
}
public void addNewAccount(final String accountName)
{
mStrings.add(mStrings.size()-2, accountName);
notifyDataSetChanged();
}
#Override
public int getCount()
{
return mStrings.size();
}
#Override
public String getItem(int position)
{
return mStrings.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public int getViewTypeCount()
{
return TYPE_MAX_COUNT;
}
#Override
public int getItemViewType(int position)
{
return position == mStrings.size()-1 ? TYPE_NEW_ACCOUNT : TYPE_ACCOUNT;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
int type = getItemViewType(position);
System.out.println(position + ": " + type);
switch (type) {
case TYPE_ACCOUNT:
convertView = mInflator.inflate(R.layout.account_item, null);
CheckBox tv = (CheckBox) convertView.findViewById(R.id.account_item_cb);
tv.setText(getItem(position));
tv.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// TODO Auto-generated method stub
if (isChecked)
{
mSelectedStrings.add(buttonView.getText().toString());
}else {
mSelectedStrings.remove(buttonView.getText().toString());
}
}
});
break;
case TYPE_NEW_ACCOUNT:
convertView = mInflator.inflate(R.layout.list_new_item_add_button, null);
break;
default:
break;
}
return convertView;
}
public ArrayList<String> getSelectedStrings()
{
return mSelectedStrings;
}
}
There is an Activity calls which Populates this base adapter will an Array list of String. I am trying to show a dialog box to the user when the Add button is clicked. But I am not able to show it. I tried:
Adding android:onClick=method in the XML file and writing corresponding method in the main activity file, but Eclipse cannot find the function. I think it is looking for the function in the base adapter class. But the problem is I can't write code to show a AlertBox in the Base Adapter class because getSupportFragmentManager cannot be accessed from there.
Adding onClickListener to Button using findViewById, but Eclipse gives me NullPointerException here. I think this is because the button is placed in the ListView and not the Activity directly.
Can someone help me here?
Thanks!
Check this, follow the examples to implement an interface in the activity and pass it to your adapter when you create it.
All you need is to place the open dialog code in the interface method in the activity and call it in the adapter when you click the button.
Place this somewhere in your activity: (this could also be done by making the activity implement the interface)
public interface DialogCreatorInterface{
public void showDialog();
}
DialogCreatorInterface dialogCreatorInterface = new DialogCreatorInterface() {
#Override
public void showDialog() {
//Create and show the dialog code
}
};
Change the adapter constructor to include the interface:
AccountListAdapter(Context context, ArrayList<String> array, DialogCreatorInterface dialogCreatorInterface)
Add this under your TYPE_NEW_ACCOUNT in the getView method:
Button button = (Button) convertView.findViewById(R.id.b_newitem);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Call open AlerDialog in activity via the interface
dialogCreatorInterface.showDialog();
}
});
You need to implement
OnItemClickListener
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3)
Following is some test code , done to recreate a strange bug: After deleting some items from a ListView , it stops refreshing when data is invalidated. More items are deleted but list does not refresh. Even Log cat does not show debug messages for deletion. I will appreciate if any one could find out what's wrong.
Item Layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<TextView android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button android:id="#+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Delete"
/>
</LinearLayout>
Item class:
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class Item implements View.OnClickListener {
private String name;
private View itemView;
private MyActivity owner;
//--- getters--
public String getName() {
return name;
}
public View getView() {
return itemView;
}
public Item(String n, Context c , MyActivity o)
{
//---store the name given--
name = n;
//---store reference to the owner activity--
owner = o;
//--- create a View for this item----
LayoutInflater inflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
itemView = inflater.inflate(R.layout.item,null);
//---set up data to show--
TextView nameTextView = (TextView) itemView.findViewById(R.id.nameTextView);
Button deleteButton = (Button) itemView.findViewById(R.id.deleteButton);
nameTextView.setText(name);
//---set up events to be handled--
deleteButton.setOnClickListener(this);
Log.d("My_Test","Item: Hello world, my name is " + name);
}
//----request owner to delete this item---
#Override
public void onClick(View view) {
Log.d("My_Test","Item:"+name+" requesting owner to delete me");
owner.deleteItem(this);
}
Activity layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView android:id="#+id/myListView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Activity class:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
public class MyActivity extends Activity {
private ArrayList<Item> myItems;
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//-----adapter for item list----
//----since each item has its own view , it just returns the same---
myArrayAdapter = new ArrayAdapter<Item>(this,0){
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
return item.getView();
}
};
//-----set up my list view with the adapter------
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
//------add items-------
//----each item has its own view and a reference to this activity as their owner----
myArrayAdapter.add(new Item("Sunday", this, this));
myArrayAdapter.add(new Item("Monday", this, this));
myArrayAdapter.add(new Item("Tuesday", this, this));
myArrayAdapter.add(new Item("Wednesday", this, this));
myArrayAdapter.add(new Item("Thursday", this, this));
myArrayAdapter.add(new Item("Friday", this, this));
myArrayAdapter.add(new Item("Saturday", this, this));
myArrayAdapter.notifyDataSetChanged();
}
//----- called by items requesting to be deleted from the item list----
public void deleteItem(Item item) {
myArrayAdapter.remove(item);
Log.d("My_Test","Owner : Deleted item :" + item.getName());
myArrayAdapter.notifyDataSetChanged();
}
}
Looks like ListView stops re-drawing it self. Even when List Item is no more in the item array, and myAdapter.notifyDataSetInvalidated(); is called, The List Item stays visible , with further code execution some how blocked.
Use an ArrayAdapter to do this. Try something like this instead...
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
public class MyActivity extends Activity{
private ListView myListView;
private ArrayAdapter<Item> myArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myArrayAdapter = new ArrayAdapter<Item>(this,R.layout.item){
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View returnedView = convertView;
//inflate your view here
if(returnedView == null){
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
returnedView = inflater.inflate(R.layout.item,null);
}
final Item item = getItem(position);
//set the views
if(returnedView != null){
TextView nameTextView = (TextView) returnedView.findViewById(R.id.nameTextView);
nameTextView.setText(item.getName());
Button deleteButton = (Button) returnedView.findViewById(R.id.deleteButton);
deleteButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
remove(item);
notifyDataSetChanged();
}
});
}
return returnedView;
}
};
myArrayAdapter.add(new Item("Sunday"));
myArrayAdapter.add(new Item("Monday"));
myArrayAdapter.add(new Item("Tuesday"));
myArrayAdapter.add(new Item("Wednesday"));
myArrayAdapter.add(new Item("Thursday"));
myArrayAdapter.add(new Item("Friday"));
myArrayAdapter.add(new Item("Saturday"));
myListView = (ListView) findViewById(R.id.myListView);
myListView.setAdapter(myArrayAdapter);
}
}
public class Item{
private String name;
public Item(String n){
this.name = n;
}
public String getName() {
return name;
}
}
Looking inside the working of ListViews and ListAdapters, I came to know there's a lot of recycling of objects, specifically List View Item Objects which adapters produce. Here are the lessons learnt along with solution to Original problem:
When a ListView has to draw/show a list item, it requests a View from ListAdapter, and some times (NOT ALWAYS) also provides an old View object to reuse. This reuse of objects is there so as to increase performance,there's an in built Re-Cycler in ListView to do this, why inflate new layouts for each new list item, when there are already some whose properties can be modified so that they look like the new view item. Until this point , its OK for adapter to change some text on old views and give them back, or create new ones if no recycled views are available, or even discard recyclable views and always create new one.
However, If your List Item's state is more than just some text in a TextView , that is, another object is registered as an onClickListener for your list item, or your list item has a reference to some object somewhere and vice-verca; it is NOT OK for adapter to just change appearance of the reusable Views or simply discard them. Adapter has to update entire state of a reusable item. that includes de-registering old event listeners, re-registering new ones and updating all reference to external objects that may be there.
Changed getView() method for adapter to:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Item item = getItem(position);
Log.d("My_Test","Adapter : View for Item: " + item.getName() +"is requested." );
if(convertView != null)
{
(convertView.findViewById(R.id.deleteButton))
.setOnClickListener(item);
((TextView)convertView.findViewById(R.id.nameTextView))
.setText(item.getName());
return convertView;
}
else
{
return item.getView();
}
}
NOTE: While always creating new items in this case does not cause any errors, the ListView fails to detect changes and redraw. Making use of recycled items seems to solve this.
I'd like to learn about spinner and how to change spinner text size and spinner text color.
In Android, Spinner is nothing but a combo box or list box.
It lets you viewing multiple items and allows you to select one item from the list.
Edit Your XML code like this
<Spinner android:id="#+id/Spinner01"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Your Java Class code should look like this
public class SpinnerExample extends Activity {
private String array_spinner[];
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
array_spinner=new String[5];
array_spinner[0]="1";
array_spinner[1]="2";
array_spinner[2]="3";
array_spinner[3]="4";
array_spinner[4]="5";
Spinner s = (Spinner) findViewById(R.id.Spinner01);
ArrayAdapter adapter = new ArrayAdapter(this,
android.R.layout.simple_spinner_item, array_spinner);
s.setAdapter(adapter);
}
}
The Output will look like
This site gives sample screen shot with source code
http://www.androidpeople.com/android-spinner-example
Generaly we can't edit the textsize or textcolor through simple adapter,in firstxml file we declare the spinner and firstjava file we find through spinnername.findviewbyid(id).we just create the custom adapter through xml file i.e firstly we create secondxml file in which we gives our requirements like textview,images etc. ,in textview we gives the textcolor and textsize then we create customadapterfile in java and we just inflate that xml file through layout inflater in our custom adapter and finally we pass that adapter in spinner.Your custom viewing spinner is created.
example for custom view where you set the textsize,textcolor and images also and many thing:-
In this a contact list is made and using custom adapter we inflate below xml file in
contactadapter file
xml file :-
<TextView android:text="Name:" android:id="#+id/tvNameCustomContact"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="10dip" android:textColor="#color/darkcherryred"
/>
<TextView android:id="#+id/tvNumberCustomContact" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Number:" android:textColor="#color/DarkGrey" android:paddingLeft="10dip"
android:layout_below="#+id/tvNameCustomContact"
/>
<TextView android:text="Group:" android:id="#+id/tvGroupCustomContact"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textColor="#color/darkcherryred" android:paddingLeft="10dip"
android:layout_below="#+id/tvNumberCustomContact"/>
custom adapter file:-
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
public class ContactAdapter extends BaseAdapter
{
private ArrayList<String> name=new ArrayList<String>();
private ArrayList<String> number=new ArrayList<String>();
private ArrayList<String> group=new ArrayList<String>();
private LayoutInflater mInflater;
public ContactAdapter(Context context, ArrayList<String> name,ArrayList<String> number,ArrayList<String> group1)
{
this.mInflater = LayoutInflater.from(context);
this.name=name;
this.number=number;
this.group=group1;
}
public int getCount() {
return this.name.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
final ViewHolder holder;
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.contactcustomlist, null);
holder = new ViewHolder();
holder.Name = (TextView) convertView.findViewById(R.id.tvNameCustomContact);
holder.Number= (TextView) convertView.findViewById(R.id.tvNumberCustomContact);
holder.Group= (TextView) convertView.findViewById(R.id.tvGroupCustomContact);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.Name.setText ("Name : "+name.get(position));
holder.Number.setText("Numbers : "+number.get(position));
holder.Group.setText ("Group : "+group.get(position));
return convertView;
}
class ViewHolder {
TextView Name;
TextView Number;
TextView Group;
}
}
we assume that you create firstxml file in which spinner is defined,finally in firstjava file you just add the code for spinner where we pass the custom adapter:
ContactAdapter contactadapter = new ContactAdapter(this, NameA, MobileA, group);//NameA,MobileA,Group is a arraylist in which we pass the values from main java file to ContactAdapter java file
Spinner spinner= (Spinner)findviewbyid(R.id.spinnername);
spinner.setAdapter(contactadapter);
The hello-spinner tutorial is very useful.
http://developer.android.com/guide/tutorials/views/hello-spinner.html
Add a new XML file to your layout folder.
android:textColor="#FF8B1500"
android:gravity="center"/>
Change the adapter resource to your new layout file:
adapter = ArrayAdapter.createFromResource(
this, R.array.sound, R.layout.spinnerLayout);
`