Im making an android game that only needs to recognize swipes. However, the onFling method is never called for some reason. I have no issue with modifying onScroll or other methods just so that onFling works. The GestureDetectGridView is just a basic class that calls the gridView super constructor. The Movement Controller is definitely correct as well. So the issue has to be in this class.
public class TwentyGestureDetectGridView extends GestureDetectGridView implements View.OnTouchListener, GestureDetector.OnGestureListener {
private static final int SWIPE_MIN_DISTANCE = 100;
private final GestureDetector gDetector;
private TwentyMovementController mController;
public TwentyGestureDetectGridView(Context context) {
super(context);
gDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener());
mController = new TwentyMovementController();
}
public TwentyGestureDetectGridView(Context context, AttributeSet attrs) {
super(context, attrs);
gDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener());
mController = new TwentyMovementController();
}
public TwentyGestureDetectGridView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
gDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener());
mController = new TwentyMovementController();
}
public void onSwipeUp(){}
public void onSwipeDown(){}
public void onSwipeLeft() {}
public void onSwipeRight() {}
public boolean onTouch(View v, MotionEvent event) {
return gDetector.onTouchEvent(event);
}
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_MIN_DISTANCE) {
if (distanceX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
return true;
} else if (Math.abs(distanceY) > Math.abs(distanceX) && Math.abs(distanceY) > SWIPE_MIN_DISTANCE) {
if (distanceY > 0) {
onSwipeUp();
} else {
onSwipeDown();
}
return true;
}
return false;
}
#Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {return true;}
You are missing a call to View.setOnTouchListener
For the view you want to register swipes in (probably your base layout), call view.setOnTouchListener(your listener here)
Maybe like this:
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstance){
View root = somehowCreateView();
root.setOnTouchListener(this);
return root;
}
public class TwentyGameActivity extends GameActivity implements Observer {
TwentyBoardManager twentyBoardManager;
private TwentyGestureDetectGridView gridView;
private static int columnWidth, columnHeight;
ArrayList<Button> tileButtons;
public void display() {
updateTileButtons();
gridView.setAdapter(new CustomAdapter(tileButtons, columnWidth, columnHeight));
}
private void createTileButtons(Context context){
TwentyBoard board = twentyBoardManager.getBoard();
tileButtons = new ArrayList<>();
for (int row = 0; row != board.getNumRows(); row++) {
for (int col = 0; col != board.getNumCols(); col++) {
Button tmp = new Button(context);
tmp.setBackgroundResource(board.getTile(row, col).getBackground());
this.tileButtons.add(tmp);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
twentyBoardManager = (TwentyBoardManager) Savable.loadFromFile(TEMP_SAVE_FILENAME);
createTileButtons(this);
setContentView(R.layout.activity_twenty_game);
gridView = findViewById(R.id.gridTwenty);
gridView.setNumColumns(twentyBoardManager.getSize());
gridView.setBoardManager(twentyBoardManager);
twentyBoardManager.addObserver(this);
gridView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
gridView.getViewTreeObserver().removeOnGlobalLayoutListener(
this);
int displayWidth = gridView.getMeasuredWidth();
int displayHeight = gridView.getMeasuredHeight();
columnWidth = displayWidth / twentyBoardManager.twentyBoard.getNumCols();
columnHeight = displayHeight / twentyBoardManager.twentyBoard.getNumCols();
display();
}
});
addUndoButtonListener();
twentyBoardManager.twentyBoard.generateRandomTile();
}
private void addUndoButtonListener(){
Button undoButton = findViewById(R.id.undoTwentyButton);
undoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
twentyBoardManager.undo();
}
});
}
#Override
public void update(Observable o, Object arg) {
display();
}
private void updateTileButtons() {
TwentyBoard board = twentyBoardManager.getBoard();
int nextPos = 0;
for (Button b : tileButtons) {
int row = nextPos / board.getNumCols();
int col = nextPos % board.getNumCols();
b.setBackgroundResource(board.getTile(row, col).getBackground());
nextPos++;
}
}
}
Related
I have implemented nested scrolling in Android WebView, but when scrolling brings the AppBar to display, the bottom of the WebView is hidden by the navigation bar.
Therefore, I have avoided it by adding a margin to the WebView when the offset of the AppBar changes, but this method is simple, and when scrolling, a white gap appears at the bottom of the WebView for a moment.
WebView screenshot
Chromium scrolls nicely. Is there a clean scrolling method like Chromium where white gaps aren't visible for a moment?
Chromium screenshot
The source code is shown below.
CustomWebView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.NestedScrollingChild3;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.ViewCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.appbar.AppBarLayout;
public class CustomWebView extends WebView implements NestedScrollingChild3 {
private int mLastY;
private int[] mScrollOffset = new int[2];
private int[] mScrollConsumed = new int[2];
private int mNestedOffsetY;
private NestedScrollingChildHelper mChildHelper;
private boolean mOverScrolled = false;
private boolean mScrollable;
private boolean mScrolling;
private boolean mPageLoading;
private boolean mSwipeRefreshEnabled;
private AppBarLayout mAppBarLayout;
private SwipeRefreshLayout mSwipeRefreshLayout;
private WebViewClient mWebViewClient;
private WebChromeClient mWebChromeClient;
public CustomWebView(Context context) {
this(context, null);
}
public CustomWebView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.webViewStyle);
}
public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mChildHelper = new NestedScrollingChildHelper(this);
setNestedScrollingEnabled(true);
}
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
mOverScrolled = true;
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
MotionEvent event = MotionEvent.obtain(ev);
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
mNestedOffsetY = 0;
}
int eventY = (int) event.getY();
event.offsetLocation(0, mNestedOffsetY);
switch (action) {
case MotionEvent.ACTION_MOVE:
if (event.getPointerCount() != 1|!mOverScrolled|mPageLoading) {
mLastY = eventY;
setSwipeRefreshEnabled(false);
break;
} else if (!mScrollable && mScrolling && !canZoomIn()) {
setSwipeRefreshEnabled(false);
break;
} else if (getScrollY() == 0 && mAppBarLayout.getBottom() == mAppBarLayout.getHeight() && mScrolling) {
setSwipeRefreshEnabled(true);
break;
} else {
int deltaY = mLastY - eventY;
if (mScrolling) {
mScrolling = false;
// start NestedScroll
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
}
// NestedPreScroll
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
deltaY -= mScrollConsumed[1];
mLastY = eventY - mScrollOffset[1];
event.offsetLocation(0, -mScrollOffset[1]);
mNestedOffsetY = mScrollOffset[1];
setSwipeRefreshEnabled(false);
}
// NestedScroll
if (dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) {
event.offsetLocation(0, mScrollOffset[1]);
mNestedOffsetY = mScrollOffset[1];
mLastY -= deltaY;
setSwipeRefreshEnabled(false);
}
break;
}
case MotionEvent.ACTION_DOWN:
mLastY = eventY;
mScrolling = true;
mOverScrolled = false;
setSwipeRefreshEnabled(false);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// end NestedScroll
stopNestedScroll();
break;
default:
break;
}
return super.onTouchEvent(event);
}
// Nested Scroll implements
#Override
public void setNestedScrollingEnabled(boolean enabled) {
mChildHelper.setNestedScrollingEnabled(enabled);
}
#Override
public boolean isNestedScrollingEnabled() {
return mChildHelper.isNestedScrollingEnabled();
}
#Override
public boolean startNestedScroll(int axes) {
return mChildHelper.startNestedScroll(axes);
}
#Override
public boolean startNestedScroll(int axes, int type) {
return mChildHelper.startNestedScroll(axes, type);
}
#Override
public void stopNestedScroll() {
mChildHelper.stopNestedScroll();
}
#Override
public void stopNestedScroll(int type) {
mChildHelper.stopNestedScroll(type);
}
#Override
public boolean hasNestedScrollingParent() {
return mChildHelper.hasNestedScrollingParent();
}
#Override
public boolean hasNestedScrollingParent(int type) {
return mChildHelper.hasNestedScrollingParent(type);
}
#Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
int[] offsetInWindow) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow);
}
#Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
#Nullable int[] offsetInWindow, int type) {
return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow, type);
}
#Override
public void dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
#Nullable int[] offsetInWindow, int type, #NonNull int[] consumed) {
mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow, type, consumed);
}
#Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}
#Override
public boolean dispatchNestedPreScroll(int dx, int dy, #Nullable int[] consumed,
#Nullable int[] offsetInWindow, int type) {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
}
#Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}
#Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}
#Override
protected int computeVerticalScrollRange() {
final int verticalScrollRange = super.computeVerticalScrollRange();
mScrollable = verticalScrollRange > getHeight();
return verticalScrollRange;
}
#Override
public void setWebViewClient(WebViewClient client) {
super.setWebViewClient(client);
mWebViewClient = client;
}
#Override
public void setWebChromeClient(WebChromeClient client) {
super.setWebChromeClient(client);
mWebChromeClient = client;
}
public boolean overScrolled() {
return mOverScrolled;
}
public void setAppBarLayout(#NonNull AppBarLayout appBarLayout) {
mAppBarLayout = appBarLayout;
}
public void setMargins(int left, int top, int right, int bottom) {
ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
marginParams.setMargins(left, top, right, bottom);
setLayoutParams(marginParams);
}
public void setPageLoading(boolean pageloading) {
mPageLoading = pageloading;
}
public void setSwipeRefreshLayout(SwipeRefreshLayout layout) {
mSwipeRefreshLayout = layout;
}
public boolean isSwipeRefreshEnabled() {
return mSwipeRefreshEnabled;
}
private void setSwipeRefreshEnabled(boolean enabled) {
if (!mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshEnabled = enabled;
mSwipeRefreshLayout.setEnabled(enabled);
}
}
}
Tab.java
public class Tab extends Fragment {
...
mAppBarLayout.addOnOffsetChangedListener((layout, i) -> {
if (currentFragmentTag.contains(FRAGMENT_TAG_PREFIX_WEB)) {
Tab tab = (Tab) fm.findFragmentByTag(currentFragmentTag);
if (tab != null) {
tab.getWebView().setMargins(0, 0, 0, layout.getBottom());
if (layout.getBottom() == 0) {
layout.setElevation(0f);
} else {
layout.setElevation(getResources().getDimension(R.dimen.toolbar_elevation));
}
}
}
});
...
I had a recyclerview with an adapter and everything was cool. I added view.setOnTouchListener so that I could scroll this recyclerview along with animation and other elements on 1 screen from left to right. But after that, scrolling up and down broke in recyclerview, and onclicklistener on the elements inside it stopped working. What to do and how to fix this conflict?
At the moment I can put return false in the public boolean onTouch (View v, MotionEvent event) method; instead of return gestureDetector.onTouchEvent (event); and get a working scrolling up and down back, but left-right stops working. I can do simultaneous scrolling as in ios, when scrolling of tablecloths and collections did not break when adding the svayp to the left-right.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view.setOnTouchListener(new OnSwipeTouchListener(MainActivity.this) {
public void onSwipeRight() {
choseold = chosenow;
chosenow = chosenow - 1;
if (chosenow <= 0) {
chosenow = 5;
choseold = 6;
}
swipe();
}
public void onSwipeLeft() {
choseold = chosenow;
chosenow = chosenow + 1;
if (chosenow >= 6) {
chosenow = 1;
choseold = 0;
}
swipe();
}
});
view.setFocusableInTouchMode(true);
MyAdapterlang = new MyAdapterLang(MainActivity.this, yaziki1, yaziki2, flagi);
RVlang.setAdapter(MyAdapterlang);
mLayoutManager = new LinearLayoutManager(this);
RV1.setLayoutManager(mLayoutManager);
MyAdapter = new MyAdapterApps(MainActivity.this, childs, childs2);
RV1.setAdapter(MyAdapter);
}
}
class OnSwipeTouchListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
//return false;
}
/*public boolean onTouch(final View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
y1 = event.getY();
break;
case MotionEvent.ACTION_MOVE:
y2 = event.getY();
float deltaY = y2 - y1;
if (Math.abs(deltaY) > MIN_DISTANCE) {
return false;
} else {
return gestureDetector.onTouchEvent(event);
}
}
return gestureDetector.onTouchEvent(event);
}
private float y1, y2;
private static final int MIN_DISTANCE = 50;*/
private final class GestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
return true;
}
}
} catch (Exception exception) {
exception.printStackTrace();
}
return false;
}
}
public void onSwipeRight() {
}
public void onSwipeLeft() {
}
}
Here in ios, for example, is very simple and does not break the scrolling of collections:
- (void)viewDidLoad {
UISwipeGestureRecognizer * swipeleft=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeleft:)];
swipeleft.direction=UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeleft];
UISwipeGestureRecognizer * swiperight=[[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swiperight:)];
swiperight.direction=UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:swiperight];
}
-(void)swipeleft:(UISwipeGestureRecognizer*)gestureRecognizer
{
if (self.currentnew <= 3) {
self.whatpress = 1;
[self.buttonnew sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
-(void)swiperight:(UISwipeGestureRecognizer*)gestureRecognizer
{
if ((self.currentnew >= 1) && (self.currentnew <= 3)) {
self.whatpress = 2;
[self.buttonnew sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
Here is a video:
https://2ch.hk/pr/src/1314926/15464190246250.mp4 https://2ch.hk/pr/src/1314926/15464193253190.mp4
If you only want to hook into default touch handling implementation you must return false here
#Override
public boolean onTouch(View v, MotionEvent event) {
gestureDetector.onTouchEvent(event);//Idk if it is needed or not - out of scope
return false;
}
Otherwise touch event will be considered as consumed and wont be propagated to other handlers (that handles scrolling, clicking etc. - all that stuff that stops working for you)
I got the code below from here.
This code snaps the items of HorizontalScrollView. I tried a lot to implement this customView inside my layout but I am not able to figure out to how to attach my layout to it.
This example does add the views programmatically and calls them Features.
In XML I have done "my package name.view" but I cannot figure out how to call setFeatureItems so that my Views can be attached to it.
The snapping feature can be applied on RecyclerView easily by using SnapHelper but I haven't found anything for HorizontalScrollView.
public class HomeFeatureLayout extends HorizontalScrollView {
private static final int SWIPE_MIN_DISTANCE = 5;
private static final int SWIPE_THRESHOLD_VELOCITY = 300;
private ArrayList mItems = null;
private GestureDetector mGestureDetector;
private int mActiveFeature = 0;
public HomeFeatureLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public HomeFeatureLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HomeFeatureLayout(Context context) {
super(context);
}
public void setFeatureItems(ArrayList items){
LinearLayout internalWrapper = new LinearLayout(getContext());
internalWrapper.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
internalWrapper.setOrientation(LinearLayout.HORIZONTAL);
addView(internalWrapper);
this.mItems = items;
for(int i = 0; i< items.size();i++){
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.homefeature,null);
//...
//Create the view for each screen in the scroll view
//...
internalWrapper.addView(featureLayout);
}
setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//If the user swipes
if (mGestureDetector.onTouchEvent(event)) {
return true;
}
else if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL ){
int scrollX = getScrollX();
int featureWidth = v.getMeasuredWidth();
mActiveFeature = ((scrollX + (featureWidth/2))/featureWidth);
int scrollTo = mActiveFeature*featureWidth;
smoothScrollTo(scrollTo, 0);
return true;
}
else{
return false;
}
}
});
mGestureDetector = new GestureDetector(new MyGestureDetector());
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
//right to left
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
int featureWidth = getMeasuredWidth();
mActiveFeature = (mActiveFeature < (mItems.size() - 1))? mActiveFeature + 1:mItems.size() -1;
smoothScrollTo(mActiveFeature*featureWidth, 0);
return true;
}
//left to right
else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
int featureWidth = getMeasuredWidth();
mActiveFeature = (mActiveFeature > 0)? mActiveFeature - 1:0;
smoothScrollTo(mActiveFeature*featureWidth, 0);
return true;
}
} catch (Exception e) {
Log.e("Fling", "There was an error processing the Fling event:" + e.getMessage());
}
return false;
}
}
}
in your recycleview adapter you will have reference to HomeFeatureLayout there you can call
homeFeatureLayout.setFeatureItems(items);
EDIT
public void setFeatureItems(ArrayList items){
for(int i = 0; i< items.size();i++){
// here you need to provide layout of individual items in your horizontal scrollview
LinearLayout featureLayout = (LinearLayout) View.inflate(this.getContext(),R.layout.anyLayout,null);
//...
//display information here
//...
TextView title = (TextView)featureLayout.findviewById(R.id.title);
title.setText("view title "+item.get(i).getTitle());
ImageView image = (ImageView)featureLayout.findviewById(R.id.icon);
image.setResourceId(R.drawable.icon);
internalWrapper.addView(featureLayout);
}
}
In my new program I need objects that can be swiped to the side. I already have my animation, which is working and I tried to detect the swiping of the user in another class. The problem I have is that I don't know how to connect them. When the swipe gesture is correctly recognized a specific animation should start.
My AnimatedViewClass:
private Runnable r = new Runnable() {
#Override
public void run() {
if(continueAnimation) {
invalidate();
}
}
};
protected void onDraw(Canvas c) {
if (x<0) {
x = this.getWidth()/2-100;
y = this.getHeight()/2-100;
}
else {
x += xVelocity;
if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
boolean continueAnimation = false;
}
}
c.drawBitmap(ball.getBitmap(), x, y, null);
if(continueAnimation)
{
h.postDelayed(r, FRAME_RATE);
}
else {
x = this.getWidth()-ball.getBitmap().getWidth();
}
}
My SwipeTouchListener:
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener (Context ctx){
gestureDetector = new GestureDetector(ctx, new GestureListener());
}
#Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
}
result = true;
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
}
result = true;
} catch (Exception exception) {
exception.printStackTrace();
}
return result;
}
}
}
You can add GestureDetector to your view class just like this, and replace your code inside onFling()
public class AnimatedViewClass extends View {
GestureDetector gestureDetector;
public AnimatedViewClass(Context context) {
super(context);
gestureDetector = new GestureDetector(getContext(), new GestureDetectorListener());
}
#Override
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
}
private void onSwipeRight(){
// swipe right detected
// do stuff
invalidate();
}
private void onSwipeLeft(){
// swipe left detected
// do stuff
invalidate();
}
private class GestureDetectorListener extends
GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// onSwipeRight()
// onSwipeLeft()
return super.onFling(e1, e2, velocityX, velocityY);
}
#Override
public boolean onDown(MotionEvent e) {
return super.onDown(e);
}
}
private Runnable r = new Runnable() {
#Override
public void run() {
if(continueAnimation) {
invalidate();
}
}
};
protected void onDraw(Canvas c) {
if (x < 0) {
x = this.getWidth() / 2 - 100;
y = this.getHeight() / 2 - 100;
} else {
x += xVelocity;
if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
boolean continueAnimation = false;
}
}
c.drawBitmap(ball.getBitmap(), x, y, null);
if (continueAnimation) {
h.postDelayed(r, FRAME_RATE);
} else {
x = this.getWidth() - ball.getBitmap().getWidth();
}
}
}
I'm making a list with a linearLayout and adding TextViews depending on how many items I got in the database. Problem is that I want to be able to delete an item when I swipe left on the list. I was just wondering how to get the element (view) that you're swiping? Here's the code I got for adding a TextView.
for(int i = 0; i < nrOfTodos; i++) {
TextView v = new TextView(this);
String title = todos.get(i).getTitle();
System.out.println(title);
v.setText(title);
v.setHeight(listItemSize);
v.setAllCaps(true);
v.setTextColor(Color.parseColor("#FFD9A7"));
v.setTextSize(listItemSize/6);
v.setHorizontallyScrolling(false);
v.setMaxLines(1);
v.setEllipsize(TruncateAt.END);
v.setPadding(30, 50, 0, 0);
v.setId(i);
todoViews.add(v);
v.setOnTouchListener(new OnSwipeTouchListener(this) {
#Override
public void onSwipeLeft() {
/*
*
*
* TODO!!! NEXT PART OF MY PLAN TO WORLD DOMINATION!
*
*
*/
}
});
if(i%2 == 1) {
v.setBackgroundColor(Color.parseColor("#11FFFFFF"));
}
ll.addView(v, i);
}
and I also have this
public class OnSwipeTouchListener implements OnTouchListener {
private final GestureDetector gestureDetector;
public OnSwipeTouchListener(Context context) {
gestureDetector = new GestureDetector(context, new GestureListener());
}
public void onSwipeLeft() {
}
public void onSwipeRight() {
}
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
private final class GestureListener extends SimpleOnGestureListener {
private static final int SWIPE_DISTANCE_THRESHOLD = 50;
private static final int SWIPE_VELOCITY_THRESHOLD = 10;
#Override
public boolean onDown(MotionEvent e) {
//always return true since all gestures always begin with onDown and <br>
//if this returns false, the framework won't try to pick up onFling for example.
return true;
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float distanceX = e2.getX() - e1.getX();
float distanceY = e2.getY() - e1.getY();
if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (distanceX > 0)
onSwipeRight();
else
onSwipeLeft();
return true;
}
return false;
}
}
}
but I can't figure out how to actually get the view, get the titletext and remove that from the database (I can remove from the database, but I can't get what item was swiped ^^).
Any ideas would be greatly appreciated.
You may refer to this sample application Swipe_To_Delete
You may use ListView to list your data items which are got from the db.
Then modify the getSwipeItem() method in the MainActivity of the example, as follows.
#Override
public void getSwipeItem(boolean isRight, int position) {
[List_Of_Items].remove(position);
[Your_Adapter].notifyDataSetChanged();
}