I have been searching on ways to use the SectionIndexer on dates in my listView. I would like to show the "short date" when fast scrolling my list. I saw a post from a couple years ago with a guy saying he had it working and he had a different issue, but sadly he didn't post any code for his method.
I figure I will have to do something to my custom ArrayAdapter but I am not really sure what, anyone have any ideas of where I can look for something like this?
Thanks,
-Eric
Ok so here is what I ended up doing to get it to work properly, just in case someone else in the future is looking for something similar.
private class TransactionAdapter extends ArrayAdapter<Transaction> implements SectionIndexer
{
private ArrayList<Transaction> items;
private Context context;
LinkedHashMap<String, Integer> dateIndexer;
String[] sections;
public TransactionAdapter(Context context, int textViewResourceId, ArrayList<Transaction> items)
{
super(context, textViewResourceId, items);
this.context = context;
this.items = items;
this.dateIndexer = new LinkedHashMap<String, Integer>();
int size = items.size();
String prDate = " ";
for (int x = 0; x < size; x++)
{
Transaction tr = items.get(x);
Calendar date = tr.getDate();
String month = date.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
String year = String.valueOf(date.get(Calendar.YEAR));
String shortDate = month + " " + year;
if( !shortDate.equals(prDate))
{
this.dateIndexer.put(shortDate, x);
prDate = shortDate;
}
}
Set<String> sectionDates = this.dateIndexer.keySet();
// create a list from the set to sort
ArrayList<String> sectionList = new ArrayList<String>(sectionDates);
this.sections = new String[sectionList.size()];
sectionList.toArray(this.sections);
}
public int getPositionForSection(int section)
{
return dateIndexer.get(this.sections[section]);
}
public int getSectionForPosition(int position)
{
return 0;
}
public Object[] getSections()
{
return this.sections;
}
}
I found the answer in a combination of two places:
This tutorial helped me with the initial implementation of the SectionIndexter: Android ListView with fastscroll and section index
This post fixed an issue I had with the HashMap changing my ordering of my array, it suggested using a LinkedHashMap instead. is the Java HashMap keySet() iteration order consistent
You can use this library. This is the Simpliest Section Adapter available for Android's ListView. It works with list adapters that you already have. No project specific dependencies. Just include the latest jar or the sources to your Android project.
Related
What I'm trying to is making a list which contains series of numbers like [1,2,3,4,5,6...100].
In Java, it is simple using 'range' so I tried to find similar class in android.
Therefore, I found that some classes like Range and Intstream, but I don't know how to use them.
I'll be appreciated if you teach me how can I get my purpose, thanks.
You could write a simple function which would look like this:
public List<Integer> buildList(int maximum) {
List<Integer> list = new ArrayList();
for (int i = 1; i <= maximum; i++) {
list.add(i);
}
return list;
}
And a call which produces your desired result would look like this:
List<Integer> list = buildList(100);
If you want an array instead of a list, do this:
int[] array = list.toArray(new int[list.size()]);
int size = 100;
ArrayList<Integer> list = new ArrayList<>(size);
for (int i = 1; i <= size; i++) {
list.add(i);
Log.i("Value is = ", i+"");
}
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
.....
You don't need to define the size because ArrayList is dynamically
while in some other language we use list[index] to get the value.
But here we use list.get(index) to do that.
I got a very annoying problem here and I hope you can help me.
I have a List of Plants (Self defined Class). These Plants got a Name, an ID and some characteristics. The characteristics are saved in Strings.
F.e. Characteristic1 is the size of a plant, characteristic2 is the design of the leafs and so on..
I have some Spinners now, and in each of these Spinners a Selection of one characteristic should be available (Spinner1 got all characteristics from the variable characteristics1 from all plants, ...)
The goal is that I can use these Spinners to give the User the Plants, which suits to the User's Selection of the characteristics.
Any ideas how I can implement that in a non-spaghetti way? I'm a bit new to programming so I could really need your help.
I Hope I explained it well, it's quite hard for me explaining it in my second language.
My Code:
Plant - Class
private int pd_id;
private String pd_plantname;
private String pd_longinfo;
private String pd_infochar1;
private String pd_infochar2;
private String pd_infochar3;
private String pd_infochar4;
private String pd_infochar5;
Image-Class
private int i_id;
private int i_p_id;
private String i_path;
private Calendar i_date;
In my Activity i got a List of Images and a List of Plants.
To Fill a Spinner with the characteristics i use this Code.
ArrayList<String> sInfo1 = new ArrayList<String>();
while (i < plantlist.size()) {
sInfo1.add(plantlist.get(i).getPd_infochar1());
i++;
}
ArrayAdapter<String> spInfo2 = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, sInfo1);
spArt.setTag(1);
spArt.setAdapter(spInfo1);
spAlter.setOnItemSelectedListener(new MyOnItemSelectedListener(spAlter));
I got this 5 times for 5 spinners. Now to the OnItemSelectedListener
public void onItemSelected(AdapterView<?> parent, View view,
int position, long id) {
if (sp.getTag() == spAlter.getTag()) {
int i2 = 0;
while (i2 < plantlist.size()) {
if (plantlist.get(i2).getPd_infochar1()
.equalsIgnoreCase((String) sp.getSelectedItem())) {
}
else{
if(((String) sp.getSelectedItem()).equalsIgnoreCase("--Bitte auswählen--")){
}
else{
int pid = plantlist.get(i2).getPd_id();
plantlist.remove(i2);
ArrayList<Image> localIlist = getImageListFromPlantID(pid);
int x = 0;
while (x < localIlist.size()){
Toast.makeText(entscheidungsbaum.this, localIlist.get(x).getI_path(), Toast.LENGTH_SHORT).show();
imageList.remove(localIlist.get(x));
x++;
}
}
}
i2++;
}
}
So I delete for each characteristic which is wrong the images from the imagelist (which is the source for a gridview).
Firstly, this works not very well, I get some wrong images...
Secondly, that code is very bad, I know that. Can you help me find a better way to adapt the imagelist to the Spinner Selection?
Inside ArrayAdapter implementing SectionIndexer there is code that checks for list items that starts with the same first letter -- so it can be consolidated.
Like this:
alphaIndexer = new HashMap<String, Integer>();
int size = objects.length;
for (int i = 0; i < size; i++) {
// Log.d("ObjectLength", String.valueOf(objects.length));
ItemObject it = objects[i];
String name = it.name;
String s = name.substring(0, 1);
s = s.toUpperCase();
if (!alphaIndexer.containsKey(s)) {
alphaIndexer.put(s, i);
}
}
Set<String> sectionLetters = alphaIndexer.keySet();
ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);
Collections.sort(sectionList);
sections = new String[sectionList.size()];
// sectionList.toArray(sections);
for (int i = 0; i < sectionList.size(); i++)
sections[i] = sectionList.get(i);
My question, does consolidating this way effect FastScrolling? Sometimes on ListViews using SectionIndexer, the Fast Scroll isn't always smooth but "choppy". I can remove the SectionIndexer from the situation and Fast Scroll suddenly scrolls smoothly and proportionally.
ADDED CODE:
public int getPositionForSection(int section) {
return alphaIndexer.get(sections[section]);
}
public int getSectionForPosition(int position) {
return 0;
}
public Object[] getSections() {
return sections;
}
SectionIndexer does indeed affect fast scrolling.
When using a SectionIndexer, you're saying that you want users to be able to precisely jump to those sections of your data set. If data in those sections is distributed unevenly, then the fast scroller will move proportional to its progress through the set of sections instead of proportional to its progress through each individual item in the data set.
This is intentional; it's done this way so that when a user is dragging the fast scroll thumb each section is given equal weight. Precisely targeting any section is as easy as targeting any other section, even if one section only has one item and the sections on either side of it have hundreds.
I am developing an app for Android and i am using ExpandableListActivity.
I am extracting data from sqlite db which is in this format:
Id | Category | Name
CODE
here is the code that grabs the data:
List<String> groups = new ArrayList<String>();
List<String> books = new ArrayList<String>();
List<String> elecs = new ArrayList<String>();
List<List<String>> children = new ArrayList<List<String>>();
Cursor c = mDbHelper.fetchAllItems();
startManagingCursor(c);
// for all rows
for(int i=0; i<c.getCount(); i++)
{
c.moveToNext();
String t = c.getString(c.getColumnIndex("category"));
switch (getCat(t))
{
case Books:
books.add(c.getString(c.getColumnIndex("name")));
Log.d("FROM: ", c.getString(c.getColumnIndex("name")));
if(!(groups.contains("Books"))) groups.add("Books");
break;
case Electronics:
elecs.add(c.getString(c.getColumnIndex("name")));
Log.d("FROM: ", c.getString(c.getColumnIndex("name")));
if(!(groups.contains("Electronics"))) groups.add("Electronics");
break;
default:
break;
} // end switch
} // end for loop
children.add(books);
children.add(elecs);
OUTPUT
when i run this app here is how the screen looks like:
Books
Electronics
and when i click on Books or Electronics it shows everything. Like this:
Books
[c programming, perl]
[cd, laptop, psp]
Electronics
[c programming, perl]
[cd, laptop, psp]
ISSUE
i think the issue is coming from this method (getChild):
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
List<String> GRP;
List<List<String>> CHLD;
public MyExpandableListAdapter(List<String> grps, List<List<String>> chldrn) {
GRP = grps;
CHLD = chldrn;
}
...
...
public Object getChild(int groupPosition, int childPosition) {
// CHLD[groupPosition][childPosition]; ORIGINAL, where CHLD was a 2d array
return CHLD.get(childPosition); MODIFIED
}
do i have to convert my list of list of strings to a 2d array?
I cannot see how and where you use your ominous getChild(), and I don't know what CHLD is, as well as what the 'orginal' was used because a starting [XXX][XXX] is not a valid java syntax. Also Are you shure that the list of electronics is the same than the List of Books? It might be a hint that your data parsing is wrong, or the db contains invalid data.
But what might help you, is the following:
in your first sample children.get(i) will return a List<String>
I assume that there was a reason for groupPosition and childPosition inside your getChild() method. But your current implementation ignores the groupPosition totally.
Cannot help you further without knowing what exactly the issue is.
ADD according to your new Edit:
your CHLD is a List of List of Strings. correct implementation will be as following:
public class MyExpandableListAdapter extends BaseExpandableListAdapter {
List<String> GRP;
List<List<String>> CHLD;
public MyExpandableListAdapter(List<String> grps, List<List<String>> chldrn) {
GRP = grps;
CHLD = chldrn;
}
public Object getChild(int groupPosition, int childPosition) {
return CHLD.get(groupPosition).get(childPosition);
}
}
Android SDK since release of API v. 11 contains XmlAdapter sample which is also referenced from the official site. This sample appears now in at least 3 folders: android-11, android-12 and android-13. And it is broken. The main (but not only) problem it declares android.content.XmlDocumentProvider provider which is nowhere to be found including https://android.googlesource.com
There are also compilation problems in Adapters.java:
mContext cannot be resolved to a variable line 973
mFrom cannot be resolved to a variable line 938
mTo cannot be resolved to a variable line 937
mTo cannot be resolved to a variable line 939
There are few question related to this on android-developers but no answer. Did anyone managed to track this elusive XmlDocumentProvider and make the sample work?
And most importantly - dear Android team, can you ether fix the sample or pull it out?
The missing XmlDocumentProvider is now shipping with the sample in SDK 14 and the project compiles against SDK 8 and above. To run it successfully however, you must modify the manifest to point to the correct provider:
<provider android:name="com.example.android.xmladapters.XmlDocumentProvider"
android:authorities="xmldocument" />
Besides fixing the AndroidManifest.xml as pointed out by Jeff Gilfelt, you can also change the code XmlCursorAdapter class in Adapters.java (the file showing the errors) like this:
/**
* Implementation of a Cursor adapter defined in XML. This class is a thin wrapper
* of a SimpleCursorAdapter. The main difference is the ability to handle CursorBinders.
*/
private static class XmlCursorAdapter extends SimpleCursorAdapter implements ManagedAdapter {
private Context mContext;
private String mUri;
private final String mSelection;
private final String[] mSelectionArgs;
private final String mSortOrder;
private final int[] mTo;
private final String[] mFrom;
private final String[] mColumns;
private final CursorBinder[] mBinders;
private AsyncTask<Void,Void,Cursor> mLoadTask;
XmlCursorAdapter(Context context, int layout, String uri, String[] from, int[] to,
String selection, String[] selectionArgs, String sortOrder,
HashMap<String, CursorBinder> binders) {
super(context, layout, null, from, to);
mContext = context;
mUri = uri;
mFrom = from;
mTo = to;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
mColumns = new String[from.length + 1];
// This is mandatory in CursorAdapter
mColumns[0] = "_id";
System.arraycopy(from, 0, mColumns, 1, from.length);
CursorBinder basic = new StringBinder(context, new IdentityTransformation(context));
final int count = from.length;
mBinders = new CursorBinder[count];
for (int i = 0; i < count; i++) {
CursorBinder binder = binders.get(from[i]);
if (binder == null) binder = basic;
mBinders[i] = binder;
}
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
final int count = mTo.length;
final int[] to = mTo;
final CursorBinder[] binders = mBinders;
for (int i = 0; i < count; i++) {
final View v = view.findViewById(to[i]);
if (v != null) {
binders[i].bind(v, cursor, cursor.getColumnIndex(mFrom[i]));
}
}
}
......
......
......
I got the answer from the code found here:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.0.1_r1/com/example/android/xmladapters/Adapters.java?av=f
I got answer from Romain Guy, well sort of. The ticket that I opened yesterday now has a tag Status: FutureRelease which I suppose means that they will fix it in the next release. For the added reference here's link to the discussion on android-developers
I met the same error and searched around, found the same question has been asked for many times. This is how I fixed it.
There is a XmlDocumentProvider class I found.
I copied the XmlDocumentProvider.java into the XmlAdapter project and revised the AndroidManifest.xml by replacing:
<provider android:name="android.content.XmlDocumentProvider"
android:authorities="xmldocument" />
with:
<provider android:name="com.example.android.xmladapters.XmlDocumentProvider"
android:authorities="xmldocument" />
Now I am able to get the RssReaderActivity working.