Android ListView Swipe for Action like Twitter List - java

I'm trying to implement the "swipe for action" feature - like you can see in the "new" twitter app. A closer description you find at swipe for action description.
Now, are there any ideas/solution how to implement this feature?
Thanks!

Use a GestureDetector in each row, and wrap the row contents itself in a ViewFlipper. On a swipe, switch children of the ViewFlipper.
I have a ViewSwiper that combines a GestureDetector and ViewFlipper, but it is designed to work in either direction (e.g., from the regular row, a swipe left or right would switch to the actions), which may or may not be desirable. But, it should give you an idea of how this might work.

I did something similiar to what you need - you can find some info about there. I'm doing some manual stuff there but it works nice. For your convenience here is the code I've used:
OnTouchListener gestureListener = new View.OnTouchListener() {
private int padding = 0;
private int initialx = 0;
private int currentx = 0;
private ViewHolder viewHolder;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
padding = 0;
initialx = (int) event.getX();
currentx = (int) event.getX();
viewHolder = ((ViewHolder) v.getTag());
}
if (event.getAction() == MotionEvent.ACTION_MOVE) {
currentx = (int) event.getX();
padding = currentx - initialx;
}
if (event.getAction() == MotionEvent.ACTION_UP ||
event.getAction() == MotionEvent.ACTION_CANCEL) {
padding = 0;
initialx = 0;
currentx = 0;
}
if (viewHolder != null) {
if (padding == 0) {
v.setBackgroundColor(0xFF000000);
if (viewHolder.running)
v.setBackgroundColor(0xFF058805);
}
if (padding > 75) {
viewHolder.running = true;
v.setBackgroundColor(0xFF00FF00);
viewHolder.icon.setImageResource(R.drawable.clock_running);
}
if (padding < -75) {
viewHolder.running = false;
v.setBackgroundColor(0xFFFF0000);
}
v.setPadding(padding, 0, 0, 0);
}
return false;
}
};

Related

Picure Click to Picture Drag in Android Puzzle game

I Have tried with all possible ways which is suggested in StackOverflow
But i can't able to change from click to drag
OnTouch event is used for click.. and my images get clicked in this. and i can't able to drag and drop the image. i need to drag the image instead of clicking...
I will be much thankful to you. if you help me on this part
i have also tried this scenario's
Drag and Drop and OnClick TextView
But i didn't get any result. so please can anyone help me!!!!!!!
Can anyone help me in this ??
public class TouchListener implements View.OnTouchListener {
private float xDelta;
private float yDelta;
private PuzzleActivity activity;
public TouchListener(PuzzleActivity activity) {
this.activity = activity;
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getRawX();
float y = motionEvent.getRawY();
final double tolerance = sqrt(pow(view.getWidth(), 2) + pow(view.getHeight(), 2)) / 10;
PuzzlePiece piece = (PuzzlePiece) view;
if (!piece.canMove) {
return true;
}
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
xDelta = x - lParams.leftMargin;
yDelta = y - lParams.topMargin;
piece.bringToFront();
break;
case MotionEvent.ACTION_MOVE:
lParams.leftMargin = (int) (x - xDelta);
lParams.topMargin = (int) (y - yDelta);
view.setLayoutParams(lParams);
break;
case MotionEvent.ACTION_UP:
int xDiff = abs(piece.xCoord - lParams.leftMargin);
int yDiff = abs(piece.yCoord - lParams.topMargin);
if (xDiff <= tolerance && yDiff <= tolerance) {
lParams.leftMargin = piece.xCoord;
lParams.topMargin = piece.yCoord;
piece.setLayoutParams(lParams);
piece.canMove = false;
sendViewToBack(piece);
activity.checkGameOver();
}
break;
}
return true;
}
public void sendViewToBack(final View child) {
final ViewGroup parent = (ViewGroup)child.getParent();
if (null != parent) {
parent.removeView(child);
parent.addView(child, 0);
}
}
}

How to stop swipe at some point in ItemTouchHelpers?

I need to swipe an item at the beginning, or did a full swipe, or stopped in current point. As in the Yandex mail. I was tring to do setLeft(dx) and setRight(dx) but that's not what I need
I have class
ItemTouchHelperCallback extends ItemTouchHelper.Callback
and inside i override method
#Override
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
View itemView = viewHolder.itemView;
// not sure why, but this method get's called for viewholder that are already swiped away
if (viewHolder.getAdapterPosition() == -1) {
// not interested in those
return;
}
float height = (float) itemView.getBottom() - (float) itemView.getTop();
float width = height / 3;
float temdX=0;
Bitmap icon;
if(dX > 0 || lastdX>0){
//try stop item while back in dx=0, but workin only while i debug
if(lastdX>=100 && dX==0 &&lastdX!=0 &&lastdX!=-720)
{
dX=100;
isCurrentlyActive=true;
}
lastdX=dX;
itemView.setLeft((int) dX);
p.setColor(Color.GREEN);
RectF background = new RectF((float) itemView.getLeft(), (float) itemView.getTop(), dX,(float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_y);
RectF icon_dest = new RectF((float) itemView.getLeft() + width ,(float) itemView.getTop() + width, (float) itemView.getLeft()+ 2*width,(float)itemView.getBottom() - width);
c.drawBitmap(icon, null, icon_dest, p);
} else if(lastdX<0 || dX<0) {
if(lastdX<=-100 && dX==0 &&lastdX!=0 &&lastdX!=720)
{
dX=-100;
//itemView.setTranslationX(-200);
isCurrentlyActive=true;
}
lastdX=dX;
itemView.setRight((int)(dX));
p.setColor(Color.RED);
RectF background = new RectF((float) itemView.getRight() + dX, (float) itemView.getTop(),(float) itemView.getRight(), (float) itemView.getBottom());
c.drawRect(background,p);
icon = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_x);
RectF icon_dest = new RectF((float) itemView.getRight() - 2*width ,(float) itemView.getTop() + width, (float) itemView.getRight() - width,(float)itemView.getBottom() - width);
c.drawBitmap(icon,null,icon_dest,p);
}
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
}
I needed to do something similar and at the beginning I also thought to use the callbacks provided in the ItemTouchHelper. It turned out it's not the right approach.
If you want to stop (or in general to control) the translation of the view during the swipe, you need to be able to modify and save the value of the displacement dX. If you use the ItemTouchHelper, this value is controlled outside the available callbacks.
The solution for me was the implementation of the swipe with a custom touchListener, attached in the view holder of the recycler view. You can find an example of the basic implementation here. In case you need to consider the click on the item, remember you need to implement this in the touchListener as well.
I hope this is somehow helpful.
EDIT
Here a snippet of a custom ItemTouchListener. The listener is simplified and shows only code to handle the translation on the view during swipe. In order to stop swipe, just implement limit logic on translationX under ACTION_MOVE.
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
public class ItemTouchListener implements View.OnTouchListener {
private int mSlop;
private View mView;
private float mDownX, mDownY;
private boolean mSwiping;
private int mSwipingSlop;
private VelocityTracker mVelocityTracker;
private float mTranslationX;
public ItemTouchListener(View view) {
ViewConfiguration vc = ViewConfiguration.get(view.getContext());
mSlop = vc.getScaledTouchSlop();
mView = view;
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// offset because the view is translated during swipe
motionEvent.offsetLocation(mTranslationX, 0);
switch (motionEvent.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
mDownX = motionEvent.getRawX();
mDownY = motionEvent.getRawY();
return true;
}
case MotionEvent.ACTION_UP: {
// if needed, implement part of limit swipe logic also here
if (mVelocityTracker == null) {
break;
}
mVelocityTracker.addMovement(motionEvent);
mVelocityTracker.computeCurrentVelocity(1000);
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
break;
}
case MotionEvent.ACTION_CANCEL: {
if (mVelocityTracker == null) {
break;
}
mVelocityTracker.recycle();
mVelocityTracker = null;
mTranslationX = 0;
mDownX = 0;
mDownY = 0;
mSwiping = false;
break;
}
case MotionEvent.ACTION_MOVE: {
if (mVelocityTracker == null) {
break;
}
mVelocityTracker.addMovement(motionEvent);
float deltaX = motionEvent.getRawX() - mDownX;
float deltaY = motionEvent.getRawY() - mDownY;
if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
mSwiping = true;
mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
// cancel view's touch
MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
(motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
cancelEvent.recycle();
}
if (mSwiping) {
// limit deltaX here: this will keep the swipe up to desired point
mTranslationX = deltaX;
mView.setTranslationX(deltaX - mSwipingSlop);
return true;
}
break;
}
}
return false;
}
}

ViewPager Disable Swiping

I have a ViewPager which has 3 fragments. Fragment A on the left, B in the middle and C on the right. Fragment C has a ListView which fills the whole width of the screen. I implemented a swipe listener on my ListView items using the following code:
SWIPE DETECTOR :
public class SwipeDetector implements View.OnTouchListener {
public static enum Action {
LR, // Left to Right
RL, // Right to Left
TB, // Top to bottom
BT, // Bottom to Top
None // when no action was detected
}
private static final String logTag = "SwipeDetector";
private static final int MIN_DISTANCE = 100;
private static final int VERTICAL_MIN_DISTANCE = 80;
private static final int HORIZONTAL_MIN_DISTANCE = 80;
private float downX, downY, upX, upY;
private Action mSwipeDetected = Action.None;
public boolean swipeDetected() {
return mSwipeDetected != Action.None;
}
public Action getAction() {
return mSwipeDetected;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
downY = event.getY();
mSwipeDetected = Action.None;
return false; // allow other events like Click to be processed
}
case MotionEvent.ACTION_MOVE: {
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// horizontal swipe detection
if (Math.abs(deltaX) > HORIZONTAL_MIN_DISTANCE) {
// left or right
if (deltaX < 0) {
// Log.i(logTag, "Swipe Left to Right");
mSwipeDetected = Action.LR;
return true;
}
if (deltaX > 0) {
// Log.i(logTag, "Swipe Right to Left");
mSwipeDetected = Action.RL;
return true;
}
} else
// vertical swipe detection
if (Math.abs(deltaY) > VERTICAL_MIN_DISTANCE) {
// top or down
if (deltaY < 0) {
Log.i(logTag, "Swipe Top to Bottom");
mSwipeDetected = Action.TB;
return false;
}
if (deltaY > 0) {
Log.i(logTag, "Swipe Bottom to Top");
mSwipeDetected = Action.BT;
return false;
}
}
return true;
}
}
return false;
}}
I use it in the following way :
listView.setOnTouchListener(swipeDetector);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
final int position, long id) {
Log.d("CLICKED", "CLICKED");
if (swipeDetector.swipeDetected()) {
Log.d("SWIPING", "SWIPING");
Log.d("ACTION", swipeDetector.getAction().toString());
final Button del = (Button) view.findViewById(R.id.delete_button);
if (swipeDetector.getAction() == SwipeDetector.Action.LR) {
Log.d("LEFT TO RIGHT", "Left to right");
This works perfectly fine with Activities. However, the problem now is that when I swipe, it assumes I am swiping in the ViewPager and takes me back to the middle fragment. Is there a way to disable the ViewPager swiping on this ListView or change the focus so that this works?

Add dead zone to SwipeRefreshLayout Android

Is there a way to make the SwipeRefreshLayout have a small deadzone so that if the user scrolls to the top and keeps scrolling, it wont immediately try bring down the pull to refresh? i would like it to have a small dead zone because the pull to refresh is interfering with a view pager in the ListView.
if the user swipes the viewpager and moves their finger down very slightly through the drag, it starts to do the pull to refresh and the swipe motion is lost and the viewpager just resets its position.
i've tried doing something like this
mSwipeRefreshLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
p1 = new Point((int) event.getX(), (int) event.getY());
else if(event.getAction() == MotionEvent.ACTION_MOVE)
p2 = new Point((int) event.getX(), (int) event.getY());
if(p1 != null && p2 != null && Math.abs(p1.y - p2.y) < 50) {
return true;
}
return false;
}
});
and
mSwipeRefreshLayout.setOnDragListener(new View.OnDragListener() {
#Override
public boolean onDrag(View v, DragEvent event) {
if(event.getAction() == DragEvent.ACTION_DRAG_ENTERED)
p1 = new Point((int) event.getX(), (int) event.getY());
else if(event.getAction() == DragEvent.ACTION_DRAG_LOCATION)
p2 = new Point((int) event.getX(), (int) event.getY());
if(p1 != null && p2 != null && Math.abs(p1.y - p2.y) < 50) {
return true;
}
return false;
}
});
but p2 doesnt get set properly it seems so not sure what to do

Horizontal scroll view scrolling one item at time

i am currently implementing a panel that include horizontal list view using Horizontal scroll view . in that I need control the scrolling of Horizontal scroll view and do the scrolling one item at time.
could any one give me idea to do this kind of thing.
I manged to do this using overriding HorizontalScrollView and merging code i got from various internet examples .it is working fine .
i have used gestureDetector and onFling method to achieve this task.
public void setCenter(int index) {
ViewGroup parent = (ViewGroup) getChildAt(0);
View preView = parent.getChildAt(prevIndex);
//preView.setBackgroundColor(Color.parseColor("#64CBD8"));
android.widget.LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(5, 0, 5, 0);
preView.setLayoutParams(lp);
View view = parent.getChildAt(index);
//view.setBackgroundColor(Color.RED);
int screenWidth = ((Activity) context).getWindowManager()
.getDefaultDisplay().getWidth();
int scrollX = (view.getLeft() - (screenWidth / 2))
+ (view.getWidth() / 2);
this.smoothScrollTo(scrollX, 0);
prevIndex = index;
Log.d("ITEM", String.valueOf(prevIndex));
}
#Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (flingDisable)
return false;
boolean returnValue = false;
float ptx1 = 0, ptx2 = 0;
if (e1 == null || e2 == null)
return false;
ptx1 = e1.getX();
ptx2 = e2.getX();
// right to left
if (ptx1 - ptx2 > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
if (activeItem < maxItem - 1)
activeItem = activeItem + 1;
returnValue = true;
} else if (ptx2 - ptx1 > SWIPE_MIN_DISTANCE
&& Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
if (activeItem > 0)
activeItem = activeItem - 1;
returnValue = true;
}
//scrollTo = activeItem * itemWidth;
//this.smoothScrollTo(0, scrollTo);
setCenter(activeItem);
return returnValue;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
Boolean returnValue = gestureDetector.onTouchEvent(event);
int x = (int) event.getRawX();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
if (start) {
this.prevScrollX = x;
start = false;
}
break;
case MotionEvent.ACTION_UP:
start = true;
this.currentScrollX = x;
int minFactor = itemWidth / SWIPE_PAGE_ON_FACTOR;
if ((this.prevScrollX - this.currentScrollX) > minFactor) {
if (activeItem < maxItem - 1)
activeItem = activeItem + 1;
} else if ((this.currentScrollX - this.prevScrollX) > minFactor) {
if (activeItem > 0)
activeItem = activeItem - 1;
}
Log.d("ITEM", String.valueOf(activeItem));
setCenter(activeItem);
returnValue = true;
break;
}
return returnValue;
}

Categories