• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

Apps Listview OnItemLongClick and getView [SOLVED]

I put a log.d in the setviewvalue method and it does get called when doing a longclick but does not go into the IF part very strange....
This is good! we're making progress :)


Also added the log.d to show the object being longclicked - seems to be textview and imageview however these are set to android:focusable="false" and android:focusableInTouchMode="false"
That's OK, it is just showing us what view the framework is passing to setViewValue. That's all we want to know here.


Further to this as there is only one imageview object I tried using the view.getid()==R.id.image_view but now where it crashes with a null point exception is when I am trying to change the background colours so in this method, using the way I did in getview does not work.
I think I see some of what is going on here -- you seem to be misunderstanding the scope of the method and when/ why it is getting called. That's OK, we're making progress with the above two results.

I'll try and post some code next.
 
[HIGH]import android.app.ListActivity;
import android.database.Cursor;
import android.graphics.Color;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;



public class MyListActivity extends ListActivity
{
private static final String TAG = "MyListActivity";

private ListView myListView;
private SimpleCursorAdapter adapter;

private int currentlySelectedItem = -1;

private ViewBinder viewBinder;
private OnItemClickListener longClickListener;



@Override
protected void onResume()
{
super.onResume();

myListView = getListView();

setupViewBinder();
setupLongClickListener();

//from your code
adapter = new SimpleCursorAdapter(this,R.layout.viewdata, mC, fields, viewfields);

adapter.setViewBinder( viewBinder) ;
myListView.setOnItemClickListener( longClickListener );
}




private void setupViewBinder()
{
viewBinder = new SimpleCursorAdapter.ViewBinder() {

@Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex)
{
Log.d( TAG, "setViewValue called to set the data on view: " + view );
Log.d( TAG, "-> setViewValue cursor at position: " + cursor.getPosition() );

if (currentlySelectedItem == cursor.getPosition() )
{
Log.d( TAG, "-> setViewValue called on a row we want to highlight!" );

if ( view.getId() == R.id.Table1 )
{
view.setBackgroundColor(Color.BLACK);

Log.d( TAG, "-> setViewValue setBackgroundColor on "+view );
}
}

return true;
}
};
}


private void setupLongClickListener()
{
longClickListener = new OnItemClickListener()
{

@Override
public void onItemClick( AdapterView< ? > parent, View v, int position, long id )
{
//we ignore id here as it is not the view ID
Log.d( TAG, "onItemClick on view: " + v );
Log.d( TAG, "-> onItemClick called on position: " + position );

MyListActivity.this.currentlySelectedItem = position;

MyListActivity.this.adapter.notifyDataSetChanged();
}


};
}

}[/HIGH]
 
The above code hopefully illustrates the most simple version of how you might accomplish this with your code. See if any of it helps :)
 
The above code hopefully illustrates the most simple version of how you might accomplish this with your code. See if any of it helps :)


Right it reaches the part where the cursor position matches the longclicked position but it does not reach the part within, where it does this:
[HIGH]
if (view.getId()==R.id.Table1) {
view.setBackgroundResource(R.drawable.darkslateblue);
Log.d("SETVALUEBKG","Setting background colour on view "+view);
}[/HIGH]

I noticed in your code example that your have your return true statement at the end of the setviewvalue where as I have mine false as each if condition is set to true. However I have my return true within the if cursor.getPosition()==selecteditemlongclicked, not sure if this is relevant or not.

**EDIT**

I haven even tried the return true at the end of the setviewvalue and this made no difference. So for some reason it cannot match the R.id.Table1 .

Thanks

TimCS
 
So when you setup your SimpleCursorAdapter, do you pass it a list of view that it is supposed to bind?

Sorry confused by this question unless you mean this :
[HIGH]
adapter = new SimpleCursorAdapter(this,R.layout.viewdata, mC, fields, viewfields);[/HIGH]

fields are :

[HIGH]String[] fields = new String[] {DBAdapter.COL_TYPE,DBAdapter.COL_IMAGE,DBAdapter.COL_INFO, DBAdapter.COL_DAY,DBAdapter.COL_MON,DBAdapter.COL_YEAR,DBAdapter.COL_HOUR,DBAdapter.COL_MIN,DBAdapter.COL_SEC,DBAdapter.COL_DAY};[/HIGH]

mC is the cursor and viewfields are :
[HIGH]
int[] viewfields = new int[] {R.id.image_type,R.id.type_view,R.id.info_view ,R.id.date_day_view,R.id.date_month_view,R.id.date_year_view,R.id.time_hour_view,R.id.time_min_view,R.id.time_sec_view,R.id.seper};[/HIGH]

Do you mean add the table view in the viewfields even though it does not have a database field to link to? I presume (it has been a while since I look at my code ) this is how I did it for the separator (R.id.seper), in that I just linked it to any field.

Thought I'd give it ago added the R.id.Table1 to the viewfields and just added the DBAdapter.COL_DAY again, tried to run it but the app crashed straight away with :

[HIGH]09-28 17:59:01.389: E/AndroidRuntime(18665): java.lang.IllegalStateException: android.widget.TableLayout is not a view that can be bounds by this SimpleCursorAdapter
09-28 17:59:01.389: E/AndroidRuntime(18665): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:140)[/HIGH]

Thanks

TimCS
 
Do you mean add the table view in the viewfields even though it does not have a database field to link to?
Yes.

I guess you may need to try using another type of view and make sure you have a matching number of columns though.

Ultimately though we're kinda hacking our way around how a SimpleCursorAdapter is supposed to work.


The other thing you could try is when a view is passed to setViewValue, try accessing that view's parent. (depends on the xml layout, but you should be able to guess what the parent is)

Something like:

[HIGH]

Log.d("SETVALUEBKG","parent view = "+view.getParent());

if (view.getParent().getId()==R.id.Table1)
{
view.setBackgroundResource(R.drawable.darkslateblue);

}
[/HIGH]
 
Yes.

I guess you may need to try using another type of view and make sure you have a matching number of columns though.

Ultimately though we're kinda hacking our way around how a SimpleCursorAdapter is supposed to work.


The other thing you could try is when a view is passed to setViewValue, try accessing that view's parent. (depends on the xml layout, but you should be able to guess what the parent is)

Something like:

[HIGH]

Log.d("SETVALUEBKG","parent view = "+view.getParent());

if (view.getParent().getId()==R.id.Table1)
{
view.setBackgroundResource(R.drawable.darkslateblue);

}
[/HIGH]

Hi again alostpacket . tried to add as you suggested the code given but when I type view.getParent().getId() I the getId() does not appear as an option from the list of methods.

However I will try the debug to see which parent(s) are used

** EDIT **

tried the following after finding out from the log cat logs that the parent varied between a TableLayout and a TableRow . However what I have tried now only highlights all of the child views not the TableLayout or Row which means that the row does not look right when highlighted :

[HIGH]Log.d("SETVALUEBKG","Parent of view "+view.getParent());
if (view.getParent() instanceof TableLayout || view.getParent() instanceof TableRow ) {
Log.d("SETVALUEBKG","Setting background colour on view "+view);
view.setBackgroundResource(R.drawable.darkslateblue);
}
[/HIGH]
Thanks

TimCS
 
Aweomse news, it actually sounds like you have found out how to highlight things from setViewValue.

I'm not sure how you want it to look, but it should be doable if you structure your XML by putting in a background view around something you want to highlight.

One more tip, but I think you are on your way to figuring this out :)

You can usually cast a View's Parent to a view.
[HIGH]
View myParentView = (View) view.getParent();[/HIGH]

Then you can call...

[HIGH]myViewParent.getId(); [/HIGH]

...just like a regular view.
 
Aweomse news, it actually sounds like you have found out how to highlight things from setViewValue.

I'm not sure how you want it to look, but it should be doable if you structure your XML by putting in a background view around something you want to highlight.

One more tip, but I think you are on your way to figuring this out :)

You can usually cast a View's Parent to a view.
[HIGH]
View myParentView = (View) view.getParent();[/HIGH]

Then you can call...

[HIGH]myViewParent.getId(); [/HIGH]

...just like a regular view.

I did find another way of getting the parent id by doing :

[HIGH]((View)view.getParent()).getId();[/HIGH]

and used this in the if condition.

My goal is to highlight the entire row but all it is doing is highlighting the individual child views such as the textView and the ImageView and I cannot see how to get it to highlight the table views or the LinearLayout view which fill the parent.

It may be that where I have kept this code could be in the wrong place. I am still using the original if section but have done as follows:
[HIGH]
if (cursor.getPosition()==longrowclick1) {

Log.d("SETVALUEPOS","Cursor matches clicked position! ");
Log.d("SETVALUEBKG","Parent of view "+view.getParent());
if (((View)view.getParent()).getId()==R.id.Table1 || ((View)view.getParent()).getId()==R.id.tableRow1 || ((View)view.getParent()).getId()==R.id.tableRow2 || ((View)view.getParent()).getId()==R.id.tableRow3 || ((View)view.getParent()).getId()==R.id.Table2 || ((View)view.getParent()).getId()==R.id.Table3 ) {
Log.d("SETVALUEBKG","Setting background colour on view "+view);
view.setBackgroundResource(R.drawable.darkslateblue);
}[/HIGH]

I do not know where to go from here to make the entire row highlighted plus if I highlight another row the first still stays highlighted.Further to this, I have just highlighted row (0) but for some reason row (6) gets highlighted as well

*** EDIT 1***

Right , using your code to get the parents view also allows for the parent to set its background so we are getting someone where now. However it still wants to highlight both the row selected and another row at the same time!

*** EDIT 2 ***

Using the original if where it checks for the selected and cursor position I now have the entire row selected but it keeps wanting to highlight other rows! here is the up to date code:

[HIGH]if (cursor.getPosition()==longrowclick1) {

Log.d("SETVALUEPOS","Cursor matches clicked position! ");
Log.d("SETVALUEBKG","Parent of view "+view.getParent());
View myviewp = (View) view.getParent();
if (((View)view.getParent()).getId()==R.id.Table1 || ((View)view.getParent()).getId()==R.id.tableRow1 || ((View)view.getParent()).getId()==R.id.tableRow2 || ((View)view.getParent()).getId()==R.id.tableRow3 || ((View)view.getParent()).getId()==R.id.Table2 || ((View)view.getParent()).getId()==R.id.Table3 ) {
Log.d("SETVALUEBKG","Setting background colour on view "+view);
view.setBackgroundResource(R.drawable.darkslateblue);
myviewp.setBackgroundResource(R.drawable.darkslateblue);
} else {
myviewp.setBackgroundColor(Color.BLACK);
}

}[/HIGH]
Thanks
TimCS
 
You have to un-highlight all that do not match cursor.getPosition()==longrowclick1

=]

is that not what the else part of the if condition does?

*** EDIT 1 ***

Ok the IF else I was using was within that IF of the cursor.getPosition()==longrowclick1

I have now had to create the myviewp View object as a global object as it does not see the defined version within the IF of the cursor.getPosition()==longrowclick1 . However the "other" row is still getting highlighted but now instead of it highlighting the whole row as it was doing before it is highlighting the individual view objects such as the textview and imageview etc.

I think I might know what is causing this but it is how to resolve it. I have (as you may have seen one of my previous posts in this thread) a separator which creates a visual coloured line whenever there is a new day of the month. This has to move back a record to determine if that record is on the same day etc that the current. I think this has something to do with it but I am trying to understand on why it moves to the 6th (really the 7th but as you know the index starts at 0) row when I long click on the 1st row which is position 0.


*** EDIT 2 ***

Cracked it now, it was related to the date separator section but it appears that the below code (which I have commented ) now works and another problem I had (which is now fixed) was when highlighted a row where the separator was above, this then blanked the separator out , now solved :

[HIGH]

// is the current cursor position the same that has been Long Clicked
if (cursor.getPosition()==longrowclick1) {

// sets up parent view of object
myviewp = (View) view.getParent();
// checks if parent view is valid (there are a lot here)
if (((View)view.getParent()).getId()==R.id.Table1 || ((View)view.getParent()).getId()==R.id.tableRow1 || ((View)view.getParent()).getId()==R.id.tableRow2 || ((View)view.getParent()).getId()==R.id.tableRow3 || ((View)view.getParent()).getId()==R.id.Table2 || ((View)view.getParent()).getId()==R.id.Table3 ) {

// If the parent views are valid set the background to dark slate blue
myviewp.setBackgroundResource(R.drawable.darkslateblue);
// if one of the child views are not the date separator then ..
if (view.getId()!=R.id.seper) {
// ... set them to the dark slate blue ...
view.setBackgroundResource(R.drawable.darkslateblue);
} else { // else if the child object is the date separator ..
// .. keep it as dark gray
view.setBackgroundColor(Color.DKGRAY);
}


return true;
}




} else {// if the cursor position does not match the Long Click Position then ..
// .. get the parent of the current child object ...
myviewp = (View) view.getParent();
// .. set the background of the parent to black ..
myviewp.setBackgroundColor(Color.BLACK);
// .. check to make sure that the child object is not the date separator ...
if (view.getId()!=R.id.seper) {
// .. and then set the child object background to black ..
view.setBackgroundColor(Color.BLACK);
} else { // .. else if it the child object is the date separator then ..
// .. set it to the dark gray background .
view.setBackgroundColor(Color.DKGRAY);
}


}
[/HIGH]


So thanks again to alostpack for your help on this matter. I would like to point out that when asking on another forum I got no reply whatsoever .


** EDIT 3 **

There is a new problem now since trying this again, it appears that any record above or below the date separator , when highlighted ends up changing to the record below it . As I am calling the notifydatachangedset which calls the viewbinder method, the separator logic is then called again and this someone causes the record to change its "Identity"

*** EDIT 4 ***

Sorted the above problem by removing the return true within this IF condition.

Thanks

TimCS
 
Back
Top Bottom