ExpandableListActivity make childItems unclickable - android

Hey I designed a help activity and I have kind of parents (groupItems) which have each one specific child.. So far there is no problem. But the childItems of the ExpandableListView are clickable by default so that they blink if you perform a click on them. And exactly that is what I want to avoid! This is the layout I use for the childs
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/grp_child"
android:paddingLeft="20dp"
android:textSize="15dp"
android:textStyle="normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Here is my source code how all that gets filled with content (this works):
public class HelpActivity extends ExpandableListActivity {
private static final String TAG = "HelpActivity";
private static final String PARENT = "parent";
private static final String CHILD = "child";
private List<HashMap<String,String>> parents;
private List<List<HashMap<String, String>>> childs;
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "Instantiated new " + this.getClass());
super.onCreate(savedInstanceState);
setContentView(R.layout.help);
parents = createParentList();
childs = createChildList();
SimpleExpandableListAdapter expListAdapter = new SimpleExpandableListAdapter(
this,
parents, // Describing data of group List
R.layout.help_group_item, // Group item layout XML.
new String[] {PARENT}, // the key of group item.
new int[] {R.id.row_name}, // ID of each group item.-Data under the key goes into this TextView.
childs, // childData describes second-level entries.
R.layout.help_child_item, // Layout for sub-level entries(second level).
new String[] {CHILD}, // Keys in childData maps to display.
new int[] {R.id.grp_child} // Data under the keys above go into these TextViews.
);
setListAdapter(expListAdapter); // setting the adapter in the list.
}
/* Creating the Hashmap for the row */
private List<HashMap<String,String>> createParentList() {
ArrayList<HashMap<String,String>> result = new ArrayList<HashMap<String,String>>();
HashMap<String,String> m = new HashMap<String,String>();
m.put(PARENT,getResources().getString(R.string.help_parent_1));
result.add(m);
m = new HashMap<String,String>();
m.put(PARENT,getResources().getString(R.string.help_parent_2));
result.add(m);
m = new HashMap<String,String>();
m.put(PARENT,getResources().getString(R.string.help_parent_3));
result.add(m);
return result;
}
/* creatin the HashMap for the children */
private List<List<HashMap<String, String>>> createChildList() {
ArrayList<List<HashMap<String, String>>> result = new ArrayList<List<HashMap<String, String>>>();
for (int i=0;i<parents.size();i++){
HashMap<String, String> sec = parents.get(i);
ArrayList<HashMap<String, String>> secChild = new ArrayList<HashMap<String, String>>();
HashMap<String,String> child = new HashMap<String,String>();
if(sec.containsValue(getResources().getString(R.string.help_parent_1))){
child.put(CHILD, getResources().getString(R.string.help_child_1));
}else if(sec.containsValue(getResources().getString(R.string.help_parent_2))){
child.put(CHILD, getResources().getString(R.string.help_child_2));
}else if(sec.containsValue(getResources().getString(R.string.help_parent_3))){
child.put(CHILD, getResources().getString(R.string.help_child_3));
}else if(sec.containsValue(getResources().getString(R.string.help_parent_4))){
child.put(CHILD, getResources().getString(R.string.help_child_4));
}
secChild.add(child);
result.add(secChild);
}
return result;
}
}
what I wanna to do is to make the textview the childs unclickable: I already tried the textview attributes but no one had an effect
android:clickable="false"
android:focusable="false"
android:enabled="false"
Thanks in advance to anybody who might have an idea!

You need to customise your own ExpandableListAdapter, for example by extending SimpleExpandableListAdapter, and override the .newChildView() and .getChildView() methods. In those overrided methods, you customise by setting the child view's OnClickListener and OnLongClickListener both to null.
#Override
public View newChildView(boolean isLastChild, ViewGroup parent) {
View v = super.newChildView(isLastChild, parent);
v.setOnClickListener(null);
v.setOnLongClickListener(null);
return v;
}
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
View v = super.getChildView(groupPosition, childPosition, isLastChild, convertView, parent);
v.setOnClickListener(null);
v.setOnLongClickListener(null);
return v;
}
A View's Clickable property only determines whether or not it's state will change to 'pressed' when clicked, it does not play a role in whether the View can get clicked or not. An ExpandableListAdapter sets default Listeners to its group and child Views, so you must remove them to remove any "reaction" to clicks, focus, etc.

Try this:
getExpandableListView().setOnChildClickListener(null);

Related

Prevent ListView Item refresh when adding another Item dynamically using Android

I am using BaseAdapter to bind Custom ListView. And I am adding Items dynamically. Each Item contains TextView, EditText, Spinner. It is working fine. But now issue is that if user selects any value from Spinner, add some data in EditText and then if he/she adds new item then it clears all values of filled up data.
So, I want to prevent this refresh of already added Items when add new Item. How to do this ?
My Code :
ArrayList<HashMap<String, String>> aaName = new ArrayList<HashMap<String, String>>();
HashMap<String, String> map = null;
map = new HashMap<String, String>();
map.put("Name", Name value);
aaName.add(map);
NameAdapter nameAdapter = new NameAdapter(getActivity(), aaName);
lvName.setAdapter(nameAdapter);
public class NameAdapter extends BaseAdapter {
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
if (convertView == null)
vi = inflater.inflate(R.layout.chiefcomment_view, null);
TextView tvName = (TextView) vi.findViewById(R.id.tvName);
Spinner spnTime = (Spinner) vi.findViewById(R.id.spnTime);
EditText etSpecification = (EditText) vi.findViewById(R.id.etSpecification);
HashMap<String, String> name = new HashMap<String, String>();
name = data.get(position);
tvName.setText(name.get("Name"));
// Time Spinner...
ArrayList<String> Time = new ArrayList<String>();
for (int i = 1; i <= 100; i++) {
Time.add(String.valueOf(i));
}
aaTime = new ArrayAdapter<String>(activity, R.layout.small_spinner_view, Time);
spnTime.setAdapter(aaTime);
return vi;
}
}

How do I dynamically update a spinner using ArrayList?

I have created a Spinner that is populated with an ArrayList. I want to dynamically add values to the ArrayList, so the the Spinner populates dynamically. However, when I try to add values to my ArrayList, I get a NullPointerException.
What am I missing? Do I have to reset the adapter before amending the ArrayList?
Here is my code:
My spinner, arraylist, and adapter:
deleteselection = (Spinner)view.findViewById(R.id.deletespinner);
portfoliosdelete = new ArrayList<String>();
portfoliosdelete.add("Select Portfolio");
adapterdeletetype = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item,portfoliosdelete){
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
View v = null;
// If this is the initial dummy entry, make it hidden
if (position == 0) {
TextView tv = new TextView(getContext());
tv.setHeight(0);
tv.setVisibility(View.GONE);
v = tv;
}
else {
// Pass convertView as null to prevent reuse of special case views
v = super.getDropDownView(position, null, parent);
}
// Hide scroll bar because it appears sometimes unnecessarily, this does not prevent scrolling
parent.setVerticalScrollBarEnabled(false);
return v;
}
};
adapterdeletetype.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
deleteselection.setAdapter(adapterdeletetype);
My code to dynamically update spinner:
else if(users.contains(usernull)){
pn1 = enterportfolioname.getText().toString();
user1 = new PortfolioRecord(pn1, "someemail#gmail.com");
users.remove(usernull);
users.add(user1);
portfoliosdelete.add(pn1); // <-- This causes a null pointer exception
adapterdeletetype.notifyDataSetChanged();
portfoliolist.invalidateViews();
Use the code below. This code will add a new item when the user selects and add a new item from the spinner.
Code sample:
layout main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:weightSum="10" >
<Spinner
android:id="#+id/cmbNames"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
layout spinner_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Activity class:
public class MainActivity extends Activity {
private static final String NAME = "name";
private static final String ADD_NEW_ITEM = "Add New Item";
private SimpleAdapter adapter;
private Spinner cmbNames;
private List<HashMap<String, String>> lstNames;
private int counter;
private OnItemSelectedListener itemSelectedListener = new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
HashMap<String, String> map = lstNames.get(arg2);
String name = map.get(NAME);
if (name.equalsIgnoreCase(ADD_NEW_ITEM)) {
lstNames.remove(map);
counter++;
addNewName(String.valueOf(counter));
addNewName(ADD_NEW_ITEM);
adapter.notifyDataSetChanged();
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
populateList();
cmbNames = (Spinner) findViewById(R.id.cmbNames);
adapter = new SimpleAdapter(this, lstNames, R.layout.spinner_item,
new String[] { NAME }, new int[] { R.id.tvName });
cmbNames.setAdapter(adapter);
cmbNames.setOnItemSelectedListener(itemSelectedListener);
}
private void populateList() {
lstNames = new ArrayList<HashMap<String, String>>();
addNewName("abc");
addNewName("pqr");
addNewName("xyz");
addNewName(ADD_NEW_ITEM);
}
private void addNewName(String name) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(NAME, name);
lstNames.add(map);
}
}
Try to call delete on adapterdeletetype instead of the arraylist. If it fails, then please post your logcat output.

How to inflate a expandable list in Android?

i want to inflate a expandable list with some different text and different images on each row if i use albumCovers.get(i) instead of getResources().getDrawable(R.drawable.icon)then it throws an error, any one help us out? thanks ;p.
public class ExpandActivity extends ExpandableListActivity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Construct Expandable List
final String NAME = "name";
final String IMAGE = "image";
final LayoutInflater layoutInflater = (LayoutInflater) this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final ArrayList<HashMap<String, String>> headerData = new ArrayList<HashMap<String, String>>();
final HashMap<String, String> group1 = new HashMap<String, String>();
group1.put(NAME, "Group 1");
headerData.add(group1);
final ArrayList<ArrayList<HashMap<String, Object>>> childData = new ArrayList<ArrayList<HashMap<String, Object>>>();
final ArrayList<HashMap<String, Object>> group1data = new ArrayList<HashMap<String, Object>>();
childData.add(group1data);
Resources res = this.getResources();
Drawable photo = (Drawable) res.getDrawable(R.drawable.icon);
ArrayList<Drawable> albumCovers = new ArrayList<Drawable>();
albumCovers.add(photo);
// Set up some sample data in both groups
for (int i = 0; i < 10; ++i) {
final HashMap<String, Object> map = new HashMap<String, Object>();
map.put(NAME, "Child " + i);
map.put(IMAGE, getResources().getDrawable(R.drawable.icon));
(group1data).add(map);
}
setListAdapter(new SimpleExpandableListAdapter(this, headerData,
android.R.layout.simple_expandable_list_item_1,
new String[] { NAME }, // the name of the field data
new int[] { android.R.id.text1 }, // the text field to populate
// with the field data
childData, 0, null, new int[] {}) {
#Override
public View getChildView(int groupPosition, int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final View v = super.getChildView(groupPosition, childPosition,
isLastChild, convertView, parent);
// Populate your custom view here
((TextView) v.findViewById(R.id.name))
.setText((String) ((Map<String, Object>) getChild(
groupPosition, childPosition)).get(NAME));
((ImageView) v.findViewById(R.id.image))
.setImageDrawable((Drawable) ((Map<String, Object>) getChild(
groupPosition, childPosition)).get(IMAGE));
return v;
}
#Override
public View newChildView(boolean isLastChild, ViewGroup parent) {
return layoutInflater.inflate(
R.layout.expandable_list_item_with_image, null, false);
}
});
}
}
You have only one drawable in albumCovers but loop it ten times in the for loop and try to access it by the index. Change albumCovers.get(i) to albumCovers.get(0) for it to work.
Here is the key location:
Drawable photo = (Drawable) res.getDrawable(R.drawable.icon);
ArrayList<Drawable> albumCovers = new ArrayList<Drawable>();
albumCovers.add(photo); // HERE: photo added only once!
for (int i = 0; i < 10; ++i) {
final HashMap<String, Object> map = new HashMap<String, Object>();
map.put(NAME, "Child " + i);
map.put(IMAGE, getResources().getDrawable(R.drawable.icon)); // HERE: you wanted to use albumCovers.get(i) here. There is only 1 photo in albumCovers but you try to get images 0...9 from it using index i. So, change this to albumCovers.get(0) OR add 10x photo into albumCovers.
(group1data).add(map);
}

How to use ImageViews with Expandable Lists in Android?

I have an expandable list in android and I can fill it with string easily but now I want to add a drawable on each row of the list (a different one on each row), what's the easiest way to do this with the code I already have? Thanks.
public class Physical extends ExpandableListActivity {
public static final int GROUPS = 1;
public SimpleExpandableListAdapter expListAdapter;
private boolean expanded = true;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.phys_sub);
String [] cats = { "phy1", "phys2" };
List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
for (int i = 0; i < GROUPS; i++) {
Map<String, String> curGroupMap = new HashMap<String, String>();
groupData.add(curGroupMap);
curGroupMap.put( "group", "Categories" );
List<Map<String, String>> children = new ArrayList<Map<String, String>>();
for( int n = 0 ; n < cats.length ; n++ ) {
Map<String, String> curChildMap = new HashMap<String, String>();
curChildMap.put( "child", cats[n] );
children.add(curChildMap);
}
childData.add(children);
}
expListAdapter =
new SimpleExpandableListAdapter(
/* context */
this,
/* creates Group list */
groupData,
/*Group item layout XML */
R.layout.group_row,
/* the key of each group element (not child's) */
new String[] { "group" },
/* data under the key goes into this TextView */
new int[] { R.id.group_text },
/* creates Child List (sub-level entries) */
childData,
/* layout for children in list */
R.layout.child_sub,
/* the key of each child element */
new String[] { "child" },
/* data under the child keys go into this textView */
new int[] { R.id.child_text }
);
/* sets up and initializes the adapter for the list */
setListAdapter(expListAdapter);
getExpandableListView().setOnGroupExpandListener( new OnGroupExpandListener() {
public void onGroupExpand(int groupPosition) {
expanded = true;
}
});
getExpandableListView().setOnGroupCollapseListener( new OnGroupCollapseListener() {
public void onGroupCollapse(int groupPosition) {
expanded = false;
}
});
if (expanded != false ) {
getExpandableListView().expandGroup(0);
}
}
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, final int childPosition, long id) {
switch (childPosition) {
case 0:
Intent spine_plus_intent = new Intent(Physical.this, SpinePlus.class);
startActivity(spine_plus_intent);
finish();
break;
}
return true;
}
}
you'd define a custom expandable list adapter and redefine the getchildview / getgroupview.
From there you have 2 routes to follow: one, you can programmatically add the imageviews into the child/group view (i'd discourage you from this approach), or you define an xml layout file for the child/group view and inflate it (and possibly edit the content dynamically)
Simple adapters aren't flexible enough to achieve good results. Expecially when you want custom views for their elements. (Not to mention scalability: always project and code keeping in mind that your requirements may enlarge in the future and a flexible base allows more freedom and prevents you from scratching too much code)

Android - ListView dynamic Buttons for each row calling dynamic listeners

I'm new to android, i've spent the last 2 days trying previous examples and online solutions but I just can't seem to get my head around it :(
I'm able to display a list view, parse some json from online and store a book title, book description and book ID and display this data in the listview. I want to be able to put a 'download' button in each row for the ListView, each button will correspond to its book ID on Click() and the action listener will download the book by appending that ID to a url.
e.g www.books.com/download_book1 or /download_book2....
Here is my code. Catalogue.java class
public class Catalogue extends ListActivity {
private JSONObject json;
private ListView lv;
private ArrayList<Integer> alKey = new ArrayList<Integer>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //icicle
setContentView(R.layout.shelflist);
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
....
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
map.put("id", String.valueOf(i));
map.put("title", "Title:" + e.getString("title"));
map.put("description", "Description: " + e.getString("description"));
mylist.add(map);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new SimpleAdapter(this, mylist , R.layout.shelfrow,
new String[] { "title", "description" },
new int[] { R.id.item_title, R.id.item_subtitle });
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
.....
This is as far as I get. I don't know how to add 1 button per row in the List and assign an action listener to each button.
I also have a shelfrow.xml file (textView, textView for item_title and item_subtitle) and a shelflist.xml file (ListView).
I have a shelf.xml file with
Basically you need to learn the concept of ListAdapter.
Here's the short story: picture an object that holds the data to be displayed inside a list, along with the way to display each line individually. That's your ListAdapter. Now take each individual line: it's a book with a title and an OnClickListener. It's rendered inside a View with a TextView (for the title) and a Button (for the OnClickListener). All you need to do is give one View to the adapter that will be used for each line, and a List of the books you want to be inside the list.
Here's some sample code. I hope it clears things up a bit
private class MyItemModel{ //that's our book
String title; // the book's title
String description;
long id;
OnClickListener listener = new OnClickListener(){ // the book's action
#Override
public void onClick(View v) {
// the default action for all lines
doSomethingWithTheBookTitleOrUniqueId(this);
}
};
}
private class MyListAdapter extends BaseAdapter{
View renderer;
List<MyItemModel> items;
// call this one and pass it layoutInflater.inflate(R.layout.my_list_item)
public MyListAdapter(View renderer) {
this.renderer = renderer;
}
// whenever you need to set the list of items just use this method.
// call it when you have the data ready and want to display it
public void setModel(List<MyItemModel> items){
this.items = items;
notifyDataSetChanged();
}
#Override
public int getCount() {
return items!=null?items.size():0;
}
#Override
public Object getItem(int position) {
return items!=null?items.get(position):null;
}
#Override
public long getItemId(int position) {
return items!=null?items.get(position).id:-1;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView = renderer;
}
MyItemModel item = items.get(position);
// replace those R.ids by the ones inside your custom list_item layout.
TextView label = (TextView)convertView.findViewById(R.id.item_title);
label.setText(item.label);
Button button = (Button)convertView.findViewById(R.id.item_button);
button.setOnClickListener(item.listener);
return convertView;
}
}
In order to pass the List, instead of putting the data inside your list of hashmaps you can do this for instance (be careful, I also updated the MyItemModel and MyListAdapter to your need, added the id and description properties):
List<MyItemModel> myListModel = new ArrayList<MyItemModel>();
try{
JSONArray entries = json.getJSONArray("entries");
for(int i=0;i<entries.length();i++){
MyItemModel item = new MyItemModel();
JSONObject e = entries.getJSONObject(i);
alKey.add(e.getInt("key"));
item.id = i;
item.title = e.getString("title");
item.description = e.getString("description");
// you can change the button action at this point:
// item.onClickListener = new OnClickListener(){...};
myListModel.add(item);
}
}catch(JSONException e) {
Log.e("log_tag", "Error parsing data "+e.toString());
}
ListAdapter adapter = new MyListAdapter(getLayoutInflater().inflate(R.layout.shelfrow, this));
adapter.setModel(myListModel);
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true);
You can create your own class extending ArrayAdapter that will hold your list and set onClickListener to the Button in each row.
But in getView method of your ArrayAdapter you have to create a new view every time.
for example - row layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="110dp"
android:background="#FFF"
android:layout_width="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:background="#FFF"
android:orientation="vertical"
android:padding="2dp"
android:layout_height="110dp">
<TextView android:id="#+id/list_item_title"
android:background="#FFF"
android:layout_width="fill_parent"
android:layout_height="40dp"/>
<Button android:id="#+id/download_button"
android:gravity="center"
android:text="Download"
android:layout_height="35dp"/>
</LinearLayout>
</RelativeLayout>
and getView method in ArrayAdapter
private List<Map<String, String>> jsonMapList;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.list_item, null);
// here you set textview values (title and description)
// TextView title = (TextView) v.findViewById(R.id.list_item_title);
// title.setText('bla');
// and set OnClickListener
Button button = (Button) v.findViewById(R.id.download_button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
downloadFile(getUrl(position));
}
});
return v;
}
// method that downloads file
private void downloadFile(String url) {}
// get url from your list by index
private String getUrl(int index) {
return jsonMapList.get(index).get("url");
}
Usage of Map is unnecessary, you could use any object you prefer.
In activity class
CustomAdapter listAdapter = new CustomAdapter(this, android.R.layout.simple_list_item_single_choice, jsonMapList);
setListAdapter(listAdapter);

Categories

Resources