Hi All!
I am trying to create a listView with the same row layout. But I am changing the elements of the row dynamically. From the diagram above, you can see that I populate my listView with rows but then the buttons on the row will have to be different based on the type of row. The rest of the information in the row is the same.
Is there a way I can pass a flag into the adapter to make it add/remove elements from the layout based on the type of row? My adapter extends BaseAdapter.
Yes, Make your ListView adapter take a model that contains a flag as such in my answer.
This should work if you are converting your JSON object to a specific POJO with a parser like GSON. If you are trying to load your adapter from a JSON object I would recommend against that, so good luck.
public class Row{
private RowType rowType;
//all other row attributes
}
public enum RowType{
YesNo, Cancel, //all other possible scenarios
}
public class YourAdapter extends BaseAdapter{
private List<Row> rowsToPopulate;
//Override appropriate methods
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//load your view etc....
//Check the flag to load appropriate fragment
switch(rowsToPopulate.get(position).getRowType()){
case YesNo:
//Load your yes no fragment to your row view
case Cancel:
//Load your cancel fragment to your row view
}
return yourView;
}
This information should be contained in the model that the adapter knows about.
In the getView(..) method, you should be able to check if <model>.getType() is a specific type. If so, you can set visibility of specific components in your layout and change the UI accordingly.
If the type is not a part of your response, you can keep a Map<Model, Type> inside the adapter and update the adapter when you have new data, and have a convenience method to convert this to a list of model objects to display in the UI.
Related
I have a list that I want to display differently in two fragments.
That means I need two ListViews (one in each fragment) but do I also need two adapters ? Or can I simply use one adapter for the two list given that when the data changes, I want the two lists to update.
EDIT : Display differently means I want to display the tasks sorted by alphabetical order in the first fragment and on a calendar in the second fragment.
(Or maybe there is a simpler way to go about the problem ?)
The adapter :
public class TasksAdapter extends ArrayAdapter<Task> {
public TasksAdapter(Context context, ArrayList<Task> tasks) {
super(context, 0, tasks);
}
#Override
public View getView(int position, View convertView, #NonNull ViewGroup parent) {
Task task = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_task, parent, false);
}
return convertView;
}
}
Yes, you can certainly use a single adapter if the adapter is built in such a way that it accommodates the type of data you want to use in both Fragment's.
This is dependent on the specifics of what you want to accomplish, but here are some things to consider:
Simply instantiate two separate instances of the adapter and pass the instance into the .setAdapter method of your ListView or RecyclerView.
You can programmatically use different view holders in your adapter, look into the getItemViewType() method.
If the data in your adapter is more than simple primitives, consider writing a model class to model list objects that works with both types of data you are using.
Please note, you should probably be using a RecyclerView.
I was wondering if it is possible to add subscript values to listview using a custom adapter. My adapter is expecting two List<String> and I'm using this method to populate my ListView. I looked around and a lot of people are recommending the
((TextView)findViewById(R.id.text)).setText(Html.fromHtml("X<sup>2</sup>"));
...but, I do not want the subscript applied to any additional list item that I add. I would only like it added to specific items/instance.
Fields.add("My Sample\nMy Sample\nMy Sample");
Values.add("Value\nValue\nValue");
For example I'd like to be able to pick and choose when it is applied:
Is this possible?
Rows in list view are associated with data in the adapter. To control the content of each row like applying subscript, you need to add necessary information in the data. So you cannot do it if your adapter uses solely List<String>. But if you change it to say a list of Item where Item is
class Item {
String title;
String subtitle;
}
and use List<Item> instead in the adapter. You can apply a subscript given subtitle is null or not in the adapter's getView
class MyAdapter extends ArrayAdapter<Item>{
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// assuming proper view holder pattern is applied here
Item = getItem(position);
if (item.subtitle != null){
//apply subscript state
}else{
//un-apply subscript state
}
return view;
}
}
Just like ListView in that Navigation Drawer:
Am I need to create three item-types for my custom adapter (Item with icon, separator item, item withhout icon), or I can achieve this in a simpler way?
Maybe I should to use two ListViews?
Thanks in advance.
At first use ViewHolder pattern.
At second make interfase of Item which will include two methods:
getType() - which return the type of your item;
getView(LayoutInflater inflater, View convertView) - which return the view of row. Inside this method create ViewHolder instance, then inflate View parameter to VH and do some action with result view.
. Then create 2 (or how much u need) classes which would implement Item. Define methods. Then in ListAdapter in getView() call getView() of items and return it to list.
And dont use 2ListView`. Always try to write pure code.
udenfox follow this tutorial:
http://www.android4devs.com/2014/12/how-to-make-material-design-navigation-drawer.html
I'm sure u'll get what you want.
You can try using the new recyclerview and the recyclerview adapter, which allows you to do that override the getItem method and return different items for different positions , also override getItemViewType and return differrent layouts for any position.
Pass A flag into your getview , This may not be the most efficient way i can currently think of but im pretty sure it will be of help.
A recyclerview is a really good option.
But ,
lets try to do the job with existing stuff just in case.
The following is just an example , it may not be what you want . You should look into it and grasp how it's done and implement it yourself.
Firstly how many types of list items are you gonna have ?
- let's take 3 for now.
Now Pass an integer value for each type of list item in your getview method either it goes in an array type or while parsing , for example you can have an if statement in your getview method which checks the int value in a given array item and inflates a different view depending on that value.
EXAMPLE CODE :
public View getView(final int position, View convertView, ViewGroup parent) {
// Declare Variables Globally , (here temporarily for answer)
ArrayList<HashMap<String, String>> data; // arraylist passed to custom adapter in my case
HashMap<String, String> resultp = new HashMap<String, String>(); // just a new hashmap which stores individual items from above arraylist
result = data.get(position);
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if(result.get("type")==1){
View v = inflater.inflate(R.layout.type1, parent, false);
//declare variables in your view , lets take some textview
textview.setText(result.get("something"));
return v;
}else if(result.get("type")==2){
View v = inflater.inflate(R.layout.type2, parent, false);
//take an image for example here
imageview.displayimagewithurl(result.get(url));
return v;
}else{ //type 3
View v = inflater.inflate(R.layout.type3, parent, false);
//in here lets take a layout with a textview and an image
//You know what to do ..
return v;
}
}
I'm new to Android programing. I need to create a list of 1000 goods for users to click and check or the one they want to buy. I've created the array list and added it to my custom adapter and I have also added it to my list view. my problem is how to get the position for each item selected and I need clarification on the getView and the ViewHolder. I'm not working with toast
See the below tutorials,
http://sunil-android.blogspot.in/2013/04/android-listview-checkbox-example.html
http://developerandro.blogspot.in/2013/09/listview-with-checkbox-android-example.html
http://aboutyusata.blogspot.in/2013/11/how-to-make-listview-with-checkbox-in.html
Hope it helps.
You have to use ListView getCheckedItemPositions()
/**
* Returns the set of checked items in the list. The result is only valid if
* the choice mode has not been set to {#link #CHOICE_MODE_NONE}.
*
* #return A SparseBooleanArray which will return true for each call to
* get(int position) where position is a checked position in the
* list and false otherwise, or <code>null</code> if the choice
* mode is set to {#link #CHOICE_MODE_NONE}.
*/
public SparseBooleanArray getCheckedItemPositions() {
if (mChoiceMode != CHOICE_MODE_NONE) {
return mCheckStates;
}
return null;
}
getView() method is called when new list item that is adapted is being shown on your screen. That is why you need to take good care of the memory and setTag() for every item you inflate. Then when old item is viewed again you will not render it like a new one but get it by the tag you submitted for that item.
Example: If you have 1000 items only couple of those will be shown on the screen and your program will call getView() for those items that are visible plus for couple of items bellow those that are visible so you don't see the lag in inflation while scrolling.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if(view==null)
{
LayoutInflater inflater=getLayoutInflater();
view=inflater.inflate(R.layout.list, parent, false);
TextView textView=(TextView)view.findViewById(R.id.text_hint);
ImageView imageView=(ImageView)view.findViewById(R.id.img);
// here we will setTag() our view later
}
//... (here we will manage the views and set some click listeners)
Now, what is a viewHolder?
The ViewHolder basically is the private class inside your adapter that is used to keep you inflated layout elements together and to let you manipulate those view after you got the using findViewById(int resId).
Some code:
private class ViewHolder{
public ImageView imageView;
public TextView textView;
public ViewHolder(ImageView imageView,TextView textView) {
this.imageView = imageView;
this.textView = textView;
}
}
Now to setTag() as promised.
view.setTag(new Holder(imageView,textView));
Now with this in mind you can get your ViewHolder using the code above and views that you got in the first part of my code. (this is what we will write instead of 3 dots)
ViewHolder h = (Holder) view.getTag();
h.textView.setText(ar[position]);
int resID = getResources().getIdentifier(pic[position], "drawable", getPackageName());
h.imageView.setImageResource(resID);
// here I did set some source to my imageView that is in my layout, but
// you can do whatever you want with these views. And that is what I'm
// going to explain later in this text.
return view;
}
Okay, what next?
After getting the ViewHolder from tag you have your entire layout as a View that can get his OnClickListener easily. Or just a checkBox can get OnCheckedChangeListener.
Inside methods for this listeners you can send the data to you controller (in case you are using MVC model) or to your activity that hosts this View, where you can save the state of the checkbox and title of the item that has been clicked.
For example you can do something like this on your corresponding listener method:
(MainActivity)context.markAsChecked(String title);
But in this case you will also need to have the opposite method for unchecking
(MainActivity)context.markAsUnchecked(String title);
and you will have to handle this in your MainActivity properly by browsing through the array of data that has been selected.
The second solution is to have :
(MainActivity)context.toggleState(String title);
And to handle both events checked and unchecked.
Your method in your Activity would need to do something similar to this:
public void toggleState(String title){
if (data.contains(title))
data.remove(title);
else data.add(title);
}
Then after your user checks what he wants you will have all the checked elements in your data array that in this case is ArrayList. You can also you HashMap for this if you like or something else too.
Hope this helps.
I will be more than happy to answer all of your questions if have some more.
Maybe controller implementation is something that you would like to consider in this case. That would mean that you would be using MVC model for better control of your app and data, and to delegate the tasks to responsible classes and methods. Not to put everything in one Activity :)
Bye
I have a basic object called Employee. You can retrieve an Employee's name and id using .getName() and .getId().
I want to use Jeff Sharkey's SeparatedListAdapter to build a sectioned list. For the list items though, I need to use my custom Employee objects for the items instead of just lists of Strings.
In the included examples for the SeparatedListAdapter, he uses an ArrayAdapter<String> and a SimpleAdapter() for populating the list.
Is there any way to use a custom object/class, like my Employee class? The reason I'm needing to do this, is that when I click on an item in the list, I want to retrieve the actual Employee object that I used for that item and then retrieve the ID of the employee so I can display information pertaining to that Employee.
I'm a little bit confused on how to use Adapters properly. Should I make my own adapter or something?
You'll need to implement your custom adapter. Ex:
class CustomAdapter extends ArrayAdapter<Employee>
and when use it on SeparatedListAdapter:
CustomAdapter workersAdapter = new CustomAdapter(this, resourceID, workersList);
SeparatedListAdapter separated = new SeparatedListAdapter(this);
...
separated.addSection("Workers", workersAdapter);
Edit:
Overrride getView Method in your CustomAdapter to create views with Employee info. Like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view;
if(convertView == null){
view = convertView;
}else
view = mInflater.inflate(R.layout.your_row, null);
Employee e = getItem(position);
((TextView)view.findViewById(R.id.textview_id)).setText(e.getId());
//...
return view;
}