Issues with ListView focusing - android

In my application I have a Fragment that contains both a GridView and a ListView to show items using a CursorAdapter. Only one of these two views is enabled, the user can choose the way he wants to see the items.
So, in onCreateView method of my Fragment I have
gv = (GridView) v.findViewById(R.id.itemselect_gridview);
lv = (ListView) v.findViewById(R.id.itemselect_listview);
if (!UserPreferences.isViewStyleGrid(getActivity())) {
showList();
} else {
showGrid();
}
And the code of showList and showGrid is:
private void showList() {
gv.setVisibility(View.GONE);
lv.setVisibility(View.VISIBLE);
UserPreferences.getPreferences(getActivity()).edit()
.putString(Constants.VIEWSTYLE, "list").commit();
}
private void showGrid() {
lv.setVisibility(View.GONE);
gv.setVisibility(View.VISIBLE);
UserPreferences.getPreferences(getActivity()).edit()
.putString(Constants.VIEWSTYLE, "grid").commit();
}
When the app calls showList, I cannot use a d-pad (game controller) to navigate the ListView. Pressing the d-pad keys is not effective and only touch input works.
If the app calls showGrid instead, the d-pad works properly.
If I switch from grid to list at runtime, the dpad works properly also on the ListView, the switch is made using the same methods mentioned before. What could cause this problem? I tried to use lv.setFocusable(true) and lv.requestFocus() with no results.

I realized it was too soon to call showGrid and showList, so I changed the onCreateView a little bit:
if (UserPreferences.isViewStyleGrid(mFragment.getActivity())) {
gv.post(new Runnable() {
#Override
public void run() {
showGrid();
}
});
} else {
lv.post(new Runnable() {
#Override
public void run() {
showList();
}
});
}
This way both the functions are called after the views are fully initialized.

Related

How to access adapter delete button into activity?

I have a RecyclerView and adapter. Now in that adapter, I'm inflating one row. In that row, there are one delete button and one progressbar. So what I'm doing is when user clicks on delete button, I make invisible that delete button, and make visible small progress bar in place of delete button from Adapter class. And also I'm sending position via listener to that attached activity, from that I'm calling AsyncTask.
Now the problem is:
When I got to know via AsyncTask that item is deleted, I again want to make visible delete button and to make invisible progressbar. But this time - from Activity (not from adapter), because I want to do something in activity when I get to know that item is deleted. So I can't implement AsyncTask in adapter.
code:
Adapter
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null) {
delete.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
listener.onClicked(getAdapterPosition(), eventList.get(getAdapterPosition()).getEventId());
}
}
});
Activity (in activity I want to visible/invisible adapter row button and p.bar:
#Override
public void onDeleteDataReceived(Boolean status, int position) {
stopShimmerLayout();
if (status) {
try {
eventsList.remove(position);
mAdapter.notifyItemRemoved(position);
showToast(context, "Deleted", Toast.LENGTH_SHORT);
} catch (Exception e) {
e.printStackTrace();
}
} else {
showToast(context, "Failed", Toast.LENGTH_SHORT);
}
}
See the video for better understanding: https://drive.google.com/open?id=13ZAtnyfGbi2X4JjUTmJsIDy-gt5y51Gr
To fix your problem you can take the below approach.
1) Inside your Eventpojo/model class, declare a boolean isSelectedwhich will be initially false. Now whenever user clicks the row, do `
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
eventList.get(position).isSelected=true;
delete.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
So by doing this, we are keeping in memory which object is selected and which is not, but once you recycle your views bindViewHolder will be invoked aagain and UI elements setter will be called again so put a check inside onBindViewHolder()
if(eventList.get(position).isSelected){
//show progress bar
}else{
// show delete icon
}
To remove the item, just do the following changes in your adapter-
public void removeItem(int position){
eventList.remove(position)
notifyItemRemoved(position)
}

Update a listview item row but on scroll the modifications don't remain

I have a ListView in an Android Activity and a custom adapter for that listview.
I want to be able to edit a row item and update that row instantly. This works, the modifications of the row is seen But, on scroll i loose all data.
This is my Asynk task from where i get the data and update the list row item:
/**
*
*/
public class EditNewsFeedPostAsyncTask extends AsyncTask<Void, Void, Boolean> {
public Activity context;
public String content;
public int rowPosition;
public ListView listView;
public TextView decriptionTxt;
#Override
protected Boolean doInBackground(Void... params) {
try {
token = Utils.getToken(context);
if (token != null) {
....
// {"status":"true"}
if (result != null) {
....
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
#Override
protected void onPostExecute(final Boolean success) {
if (success) {
updateListView(rowPosition, content);
}
}
public boolean updateListView(int position, String content) {
int first = listView.getFirstVisiblePosition();
int last = listView.getLastVisiblePosition();
if (position < first || position > last) {
return false;
} else {
View convertView = listView.getChildAt(position - first);
decriptionTxt.setText(content);
listView.invalidateViews();
return true;
}
}
private void updateView(int index, TextView decriptionTxt) {
View v = listView.getChildAt(index - listView.getFirstVisiblePosition());
if (v == null)
return;
decriptionTxt.setText(content);
listView.invalidateViews();
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onCancelled() {
}
}
What am i missing? shouldn't the data be persistent?
Thx
You must update the object in your listView adapter, not only the views!
after scrolling, the getView method inside your list's adapter will call and you will return the default view for that.
if you want to change that item permanent, you should update your data set and call notifyDataSetChanged on your adapter.
Make sure you're updating the data, not just the view.
When you modify the row, are you changing the underlying data or just the view? If just the view...
You're probably running into ListView recycling issues. This answer has a great explanation. Basically, ListViews are about efficiency in displaying views based on data, but are not good for holding new data on screen. Every time a ListView item is scrolled out of view, its View is recycled to be used for the item that just scrolled into view. Therefore, if you put "hi" in an EditText and then scroll it off screen, you can say goodbye to that string.
I solved this in my app by ditching ListView altogether and using an array of LinearLayouts (probably a clunky approach, but I had a known list size and it works great now). If you want to continue using a ListView, you'll have to approach it from a "data first" perspective. Like I said, ListViews are great at showing info from underlying data. If you put "hi" in an EditText and simultaneously put that string in the underlying data, it would be there regardless of any scrolling you do. Updating onTextChanged might be cumbersome, so you could also let each row open a dialog in which the user enters their data which then updates the underlying dataset when the dialog closes.
These are just some ideas, based on some assumptions, but editing views in a ListView is, in general, not very in line with how ListViews work.

Android- Listview- Buttons

I've a Listview with add button when i click add new row of buttons
created dynamically. When i scroll listview these new buttons are
visible. How can i click add buttons then the buttons are immediately
visible. Why it is happened. There is any way to handle this issue.
I've try invalidateViews() invalidate() it doesn't work. Please help me to solve this .
My sample code here
a
dd_button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
button = new Button(getApplicationContext());
linear.addView(button1, lparams);
listview.invalidateViews();
}
}
To refresh a Listview, create a ListAdapter and populate it with your items (buttons). Every time you put in it a new set of items, your list gets updated.
Check this reference on ListViews: http://developer.android.com/guide/topics/ui/layout/listview.html
you can use listview.notifyDatasetChanged() method to refresh your list.
I've solve my issue like this. Call this method
//Here running boolean value
//lv listview
private void scrollMyListViewToBottom() {
lv.post(new Runnable() {
public void run() {
if (!running) {
// Select the last row so it will scroll into view...
iv.setSelection(daily_dairy_2.getCount() - 1);
lv.invalidateViews();
running = true;
}
}
});
}

Android: ListView.getChildAt() throws null

Sometimes, when I call goToLast() it throws me a null exception in vista=lista.getChildAt(), it happens when the list is full, I dont know why I have this code:
private void goToLast() {
lista.post(new Runnable() {
#Override
public void run() {
lista.setSelection(mensajes.getCount() - 1);
View vista = lista.getChildAt(mensajes.getCount() - 1);
TextView txtMensaje = (TextView)vista.findViewById(R.id.txtMensajeLista);
txtMensaje.setBackgroundColor(Color.RED);
}
});
}
You should log lista.getChildCount(), see how many children the ListView has. ListView recycles views, which means it only hold limit number of views.
So if you want to get the last view, you should do something like this
private void goToLast() {
lista.post(new Runnable() {
#Override
public void run() {
lista.setSelection(mensajes.getCount() - 1);
// Figure out the last position of the view on the list.
int lastViewIndex = lista.getChildCount() - 1;
View vista = lista.getChildAt(lastViewIndex);
TextView txtMensaje = (TextView)vista.findViewById(R.id.txtMensajeLista);
txtMensaje.setBackgroundColor(Color.RED);
}
});
}
ListView.getChildAt() position is different to the position in your adapter. ListView recycles its views, so if you have more items in your adapter, than can fit on the screen it will not create views for all of those, but only the ones that are visible. If you want to update an item in the ListView you need to update it in the adapter and call notifyDataSetChanged()

Scrolling a ListView to a position after cursor loads

I have a fragment with a ListView, and I want the ListView to maintain its scroll position when the fragment is saved and restored. Usually this is easy, just call ListView.getFirstVisiblePosition() when saving and ListView.setSelection() (ListView.setSelectionFromTop() if you want to get fancy) when restoring.
However, I'm using loaders, and my ListView isn't fully populated when the activity starts. If I setSelection() during onActivityCreated() the list won't have anything to scroll to yet, and the call will be ignored.
I'm getting around this now by posting the scroll for sometime in the future, but this definitely isn't ideal. I'd prefer for it to scroll right as the data finishes loading. I'm almost doing that here, but swapCursor() doesn't refresh, it just schedules an invalidation for the future.
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
if (savedScrollPosition != null) {
Log.d(TAG, "loaded and scrolling to " + savedScrollPosition);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
list.setSelection(savedScrollPosition);
savedScrollPosition = null;
}
}, 100);
}
}
Do you know of any way of scrolling the ListView right as the ListView finishes populating with data?
Try this:
listView.post(new Runnable() {
#Override
public void run() {
listView.setSelection(savedScrollPosition);
savedScrollPosition = null;
}
});

Categories

Resources