Hi am using a SwipeListView that has two buttons on its back view i'm trying to programatically set the SwipeListView so that it doesn't swipe by setting the swipe mode to none. the problem i am having is the front view is now not registering the click. Does any one know why???
Heres what i have tried so far
final SwipeListView messagesList = (SwipeListView)v.findViewById(R.id.list);
if(r_deleteMessages == false || r_markMessages == false) messagesList.setSwipeMode(SwipeListView.SWIPE_MODE_NONE);
if(messageData != null){
ViewGroup.LayoutParams params = messagesList.getLayoutParams();
int size;
size = messageData.size();
params.height = (SM_Global.pxFromDp(context, 80) * size) +3;
messagesList.setLayoutParams(params);
messagesList.requestLayout();
messagesList.setFocusable(false);
final MessagesAdapter messagesAdapter = new MessagesAdapter(context, R.layout.layout_message_item, messageData,messagesList,"profile");
messagesList.setAdapter(messagesAdapter);
Log.v("Auth","CAN READ MESSAGES | " + r_readMessages);
messagesList.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public void onClickFrontView(int position) {
super.onClickFrontView(position);
Log.v("Auth","CLICKED ");
}
});
You could add a Listener to the list view and override onChangeSwipeMode
if(r_deleteMessages == false || r_markMessages == false){
mList.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public int onChangeSwipeMode(int position) {
return SwipeListView.SWIPE_MODE_NONE;
}
});
}
This way you will still get touch events.
You may also need to do mList.setSwipeOpenOnLongPress(false); to disablr the long click
see: https://github.com/47deg/android-swipelistview/issues/9
I tried the suggested ways but didn't work for me. So I made changes in my List Adapter & handled the click event there. Now it is working fine.
Related
I have one activity with one RecyclerView (SuperSlim library) and a detail activity, when I click a item of that list, detail activity will be open. The problem is when I go back, I'm trying to set the clicked element as the first visible element in the list but I get this horrible animation:
This is my onActivityReenter()
#Override
public void onActivityReenter(int resultCode, Intent data) {
super.onActivityReenter(resultCode, data);
Log.d(TAG, "onActivityReenter() called with: resultCode = [" + resultCode + "], data = [" + data + "]");
mTmpReenterState = new Bundle(data.getExtras());
int startingPosition = mTmpReenterState.getInt(EXTRA_STARTING_ITEM_POSITION);
int currentPosition = mTmpReenterState.getInt(EXTRA_CURRENT_ITEM_POSITION);
mRecycler.scrollToPosition(currentPosition);
postponeEnterTransition();
mRecycler.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mRecycler.getViewTreeObserver().removeOnPreDrawListener(this);
// TODO: figure out why it is necessary to request layout here in order to get a smooth transition.
mRecycler.requestLayout();
startPostponedEnterTransition();
return true;
}
});
}
And my SharedElementCallback:
private final SharedElementCallback exitTransitionCallBack = new SharedElementCallback() {
#Override
public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
if (mTmpReenterState == null) {
// If mTmpReenterState is null, then the activity is exiting.
View navigationBar = findViewById(android.R.id.navigationBarBackground);
View statusBar = findViewById(android.R.id.statusBarBackground);
if (navigationBar != null) {
names.add(navigationBar.getTransitionName());
sharedElements.put(navigationBar.getTransitionName(), navigationBar);
}
if (statusBar != null) {
names.add(statusBar.getTransitionName());
sharedElements.put(statusBar.getTransitionName(), statusBar);
}
} else {
int startingPosition = mTmpReenterState.getInt(EXTRA_STARTING_ITEM_POSITION);
int currentPosition = mTmpReenterState.getInt(EXTRA_CURRENT_ITEM_POSITION);
if (startingPosition != currentPosition) {
// If startingPosition != currentPosition the user must have swiped to a
// different page in the DetailsActivity. We must update the shared element
// so that the correct one falls into place.
sharedElements.clear();
sharedElements.put("number", mLayoutManager.findViewByPosition(currentPosition).findViewById(R.id.text_number));
sharedElements.put("day", mLayoutManager.findViewByPosition(currentPosition).findViewById(R.id.text_day));
sharedElements.put("recycler", mLayoutManager.findViewByPosition(currentPosition + 1).findViewById(R.id.recycler));
}
mTmpReenterState = null;
}
}
};
I think the problem is that the activity try to make an animation from the original item position to the top to the list, but I don't know how avoid that.
Does anyone know how to fix this??
Thanks in advance guys!!!
After a while I've realized that the problem that I was updating the Main Activity list with a notifyItemChanged(int) by LocalBroadcast and the standard recyclerView animation made that glitch. I solve the problem using:
RecyclerView.setItemAnimator(null)
because the standard didn't work
((SimpleItemAnimator) RecyclerView.getItemAnimator())
.setSupportsChangeAnimations(false)
So the problem is nothing to do with SharedElements.
I am using nhaarman's ListviewAnimation library https://github.com/nhaarman/ListViewAnimations which works great.
But I am facing following issues:
The main problem I am facing is, I am not able to debug my code. I have directly copy/pasted the four required libraries into libs folder. Placing a debug point inside any of the listview methods like onItemLongClick() does not work.
The second problem is, drag-drop listView is not working in my code. Whenever I try to drag any list item, on dropping the list item, the item takes the same position from which it was dragged.
Here's the code I have used:
listview.enableDragAndDrop();
listview.setDraggableManager(new TouchViewDraggableManager(
R.id.list_row_draganddrop_textview));
listview.setOnItemMovedListener(this);
listview.setOnItemLongClickListener(this);
#Override
public void onItemMoved(final int originalPosition, final int newPosition) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(getApplicationContext(), "Moved"
+ swingBottomInAnimationAdapter.getItem(newPosition)
+ newPosition, Toast.LENGTH_SHORT);
mToast.show();
}
#Override
public boolean onItemLongClick(final AdapterView<?> parent,
final View view, final int position, final long id) {
if (listview != null) {
listview.startDragging(position - listview.getHeaderViewsCount());
}
return true;
}
Whenever I try to drag any list item, on dropping the list item, the item takes the same position from which it was dragged.
Of course. Handling the change in position is your responsibility, and you should take care of it inside the onItemMoved callback:
#Override
public void onItemMoved(final int originalPosition, final int newPosition) {
if (mToast != null) {
mToast.cancel();
}
mToast = Toast.makeText(getApplicationContext(), "Moved"
+ swingBottomInAnimationAdapter.getItem(newPosition)
+ newPosition, Toast.LENGTH_SHORT);
mToast.show();
// Adapt the following to your implementation
if (originalPosition != newPosition) {
YourObject item = (YourObject) yourAdapter.getItem(originalPosition);
yourAdapter.moveItem(item, newPosition);
}
}
The method mentioned above would look something like:
public void moveItem(YourObject item, int newIndex) {
if (mEntries != null) {
mEntries.remove(item);
mEntries.add(newIndex, item);
notifyDataSetChanged();
}
}
If you go through the source code, you'll see that what you are dragging around is a Bitmap. The list item is sitting at its original position.
For others having the same problem - Niek Haarman has answered this question on GitHub here.
Don't see GitHub going down soon, but as it is good tone to paste the answer too, here it is:
#Override
public long getItemId(int position) {
return position;
}
#Override
public boolean hasStableIds() {
return true;
}
position is not a stable id here. You need a stable id for the item
which does not depend on the position.
use
import com.nhaarman.listviewanimations.ArrayAdapter;
instead of
import android.widget.ArrayAdapter;
that is the reason it doesn't calling onItemMoved
I have an app where I handle all the touches myself instead of using touch and gesture detection APIs, because it is a floating window and is the only way that works.
One of the things I do is change the color of the view under the finger.
OnTouch I check which view is under the finger if it is different from the previous I run:
myView.setBackgroundColor(getResources().getColor(R.color.white));
It doesn't work when I go to the view next to the current and return very fast.
I have checked it with logs and the view found is correct. And I have also checked and the line where setBackgroundColor is, is executed.
So I don't know what else to do. Are any cases in which setBackgroundColor doesn't work? Is it that if onTouch takes too much time to execute doesn't finish its tasks?
Any clue of how to fix this?
EDIT:
It only fails when I go to the view next to the current and return fast.
I didn't add the code because I thought it was harder to read than the abstraction I did. I have cleaned it up and posted.
If you think any methods called are relevant I can add them.
EDIT 2:
Code that runs if ACTION is not ACTION_DOWN or ACTION_UP. Those cases are not related.
if ((isPortrait && isPortraitMeasured) || (!isPortrait && isLandscapeMeasured)) {
//Log.d("algor", "Here calculate where it is");
final int lastCol = currentColumn;
final int lastRow = currentRow;
findCell((int) event.getRawX(), (int) event.getRawY());
if ((lastCol == currentColumn && lastRow == currentRow)) {
if (isPortrait && currentRow==-1 || (!isPortrait && currentColumn==-1)
&& !wasPressed && currentTable!=mainTable) {
//is actionBar. Check if finger is over back icon, to go back
//Code not related to the problem...
}
} else {
int currentIndex = getAppsListIndex();
if (currentIndex >= 0) {
View nextApp;
if (isPortrait)
nextApp = cellsP.get(currentTable).get(currentIndex);
else
nextApp = cellsL.get(currentTable).get(currentIndex);
final Object tag = nextApp.getTag();
if (tag instanceof FolderData) {
//Code not related to the problem...
} else {
Log.d("fastf", "time to change color");
//nextApp.setBackgroundColor(getResources().getColor(R.color.white));
nextApp.setBackgroundColor(whiteColor);
//nextApp.setBackground(getResources().getDrawable(R.color.white));
/*final View app = nextApp;
app.post(new Runnable() {
#Override
public void run() {
app.setBackgroundColor(getResources().getColor(R.color.white));
}
});*/
}
} else {
//Code not related to the problem...
}
int lastIndex = getAppsIndexFromInts(lastRow, lastCol);
//lastCol != -2 is because otherwise, on opening the launcher it animates
// the last app launched
if (lastIndex >= 0 && lastCol != -2) {
View lastApp;
if (isPortrait)
lastApp = cellsP.get(currentTable).get(lastIndex);
else
lastApp = cellsL.get(currentTable).get(lastIndex);
ObjectAnimator animator = ObjectAnimator.ofInt(lastApp,
"backgroundColor", getResources().getColor(R.color.clear_gray),
getResources().getColor(R.color.white_overlay_transition));
animator.setDuration(500);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
}
}
}
You should use
nextApp.setBackgroundResource(...) instead of others.
Because of your "R.color.white" is a resource.
Have a nice day.
It was an old question but, I faced same problem and resolved with this change.
try it
myView.setBackground(getResources().getDrawable(R.color.white));
myView.setBackgroundColor(getResources().getColor(R.color.bgcolor));
color.xml
<color name="bgcolor">#ffffff</color>
I'm building an interface similar to the Google Hangouts chat interface. New messages are added to the bottom of the list. Scrolling up to the top of the list will trigger a load of previous message history. When the history comes in from the network, those messages are added to the top of the list and should not trigger any kind of scroll from the position the user had stopped when the load was triggered. In other words, a "loading indicator" is shown at the top of the list:
Which is then replaced in-situ with any loaded history.
I have all of this working... except one thing that I've had to resort to reflection to accomplish. There are plenty of questions and answers involving merely saving and restoring a scroll position when adding items to the adapter attached to a ListView. My problem is that when I do something like the following (simplified but should be self-explanatory):
public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {
#Override
public void run() {
listView.setSelection(positionToSave);
}
});
}
Then what the user will see is a quick flash to the top of the ListView, then a quick flash back to the right location. The problem is fairly obvious and discovered by many people: setSelection() is unhappy until after notifyDataSetChanged() and a redraw of ListView. So we have to post() to the view to give it a chance to draw. But that looks terrible.
I've "fixed" it by using reflection. I hate it. At its core, what I want to accomplish is reset the first position of the ListView without going through the rigamarole of the draw cycle until after I've set the position. To do that, there's a helpful field of ListView: mFirstPosition. By gawd, that's exactly what I need to adjust! Unfortunately, it's package-private. Also unfortunately, there doesn't appear to be any way to set it programmatically or influence it in any way that doesn't involve an invalidate cycle... yielding the ugly behavior.
So, reflection with a fallback on failure:
try {
Field field = AdapterView.class.getDeclaredField("mFirstPosition");
field.setAccessible(true);
field.setInt(listView, positionToSave);
}
catch (Exception e) { // CATCH ALL THE EXCEPTIONS </meme>
e.printStackTrace();
listView.post(new Runnable() {
#Override
public void run() {
listView.setSelection(positionToSave);
}
});
}
}
Does it work? Yes. Is it hideous? Yes. Will it work in the future? Who knows? Is there a better way? That's my question.
How do I accomplish this without reflection?
An answer might be "write your own ListView that can handle this." I'll merely ask whether you've seen the code for ListView.
EDIT: Working solution with no reflection based on Luksprog's comment/answer.
Luksprog recommended an OnPreDrawListener(). Fascinating! I've messed with ViewTreeObservers before, but never one of these. After some messing around, the following type of thing appears to work quite perfectly.
public void addNewItems(List<Item> items) {
final int positionToSave = listView.getFirstVisiblePosition();
adapter.addAll(items);
listView.post(new Runnable() {
#Override
public void run() {
listView.setSelection(positionToSave);
}
});
listView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
#Override
public boolean onPreDraw() {
if(listView.getFirstVisiblePosition() == positionToSave) {
listView.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
else {
return false;
}
}
});
}
Very cool.
As I said in my comment, a OnPreDrawlistener could be another option to solve the problem. The idea of using the listener is to skip showing the ListView between the two states(after adding the data and after setting the selection to the right position). In the OnPreDrawListener(set with listViewReference.getViewTreeObserver().addOnPreDrawListener(listener);) you'll check the current visible position of the ListView and test it against the position which the ListView should show. If those don't match then make the listener's method return false to skip the frame and set the selection on the ListView to the right position. Setting the proper selection will trigger the draw listener again, this time the positions will match, in which case you'd unregister the OnPreDrawlistener and return true.
I was breaking up my head until I found a solution similar to this.
Before adding a set of items you have to save top distance of the firstVisible item and after adding the items do setSelectionFromTop().
Here is the code:
// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
// for (Item item : items){
mListAdapter.add(item);
}
// restore index and top position
mList.setSelectionFromTop(index, top);
It works without any jump for me with a list of about 500 items :)
I took this code from this SO post: Retaining position in ListView after calling notifyDataSetChanged
The code suggested by the question author works, but it's dangerous.
For instance, this condition:
listView.getFirstVisiblePosition() == positionToSave
may always be true if no items were changed.
I had some problems with this aproach in a situation where any number of elements were added both above and below the current element. So I came up with a sligtly improved version:
/* This listener will block any listView redraws utils unlock() is called */
private class ListViewPredrawListener implements OnPreDrawListener {
private View view;
private boolean locked;
private ListViewPredrawListener(View view) {
this.view = view;
}
public void lock() {
if (!locked) {
locked = true;
view.getViewTreeObserver().addOnPreDrawListener(this);
}
}
public void unlock() {
if (locked) {
locked = false;
view.getViewTreeObserver().removeOnPreDrawListener(this);
}
}
#Override
public boolean onPreDraw() {
return false;
}
}
/* Method inside our BaseAdapter */
private updateList(List<Item> newItems) {
int pos = listView.getFirstVisiblePosition();
View cell = listView.getChildAt(pos);
String savedId = adapter.getItemId(pos); // item the user is currently looking at
savedPositionOffset = cell == null ? 0 : cell.getTop(); // current item top offset
// Now we block listView drawing until after setSelectionFromTop() is called
final ListViewPredrawListener predrawListener = new ListViewPredrawListener(listView);
predrawListener.lock();
// We have no idea what changed between items and newItems, the only assumption
// that we make is that item with savedId is still in the newItems list
items = newItems;
notifyDataSetChanged();
// or for ArrayAdapter:
//clear();
//addAll(newItems);
listView.post(new Runnable() {
#Override
public void run() {
// Now we can finally unlock listView drawing
// Note that this code will always be executed
predrawListener.unlock();
int newPosition = ...; // Calculate new position based on the savedId
listView.setSelectionFromTop(newPosition, savedPositionOffset);
}
});
}
Can anyone guide me how set particular element of grid view as selected ?
.setSelection(positionOfItem) is not working .
gridViewSize = (GridView) inflaterView.findViewById(R.id.grid_sizes);
gridViewSize.setAdapter(new PopupSizeAdapter(context,typeArr,1));
gridViewSize.setSelection(0);
it worked for me
mGridView.setSelection(pos);
mGridView.requestFocusFromTouch();
mGridView.setSelection(pos);
I came across the same issue today, following is my solution:
GridView.getViewTreeObserver.addOnGlobalLayoutListener(getLayoutListener(mGridView))
private static ViewTreeObserver.OnGlobalLayoutListener getLayoutListener(final GridView mGridView) {
ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
View view = mGridView.getChildAt(0);
if(view != null) {
if(!view.isSelected()) {
view.setSelected(true);
} else {
// remove the listener after the first time.
if (Build.VERSION.SDK_INT < 16) {
mGridView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
mGridView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
}
}
};
return listener;
}
and also, if you are using android API >= 11, you can also add a View.OnLayoutChangeListener to GridView.
Try this:
grid.performItemClick(view, position, id);
Then my state drawable works correctly on GridView.