Swiping


#1

Hi,

If I’ve posted in the wrong place - apologies.

I’ve got to the end of chapter 10 with a working app, but then I decided on a modification I’d like to make - I’d like to be able to detect if I swipe one of the list items. If I swipe the item, I just want (for now) to display a toast message. If I click a list item(no swipe), I just want to start CrimeActivity).

After a lot of time with google and the book, I came up with the following approach (all changes in CrimeListFragment.java)

[ul]implement OnTouchListener in the CrimeAdapter class
in the existing onItemListClick method, check to see if a swipe has been detected before deciding what action to take[/ul]

I wrote the new code and made the necessary changes and when I look at the LogCat output, I can see that the onTouch handler is correctly identifying a swipe (I can’t tell you how happy that made me). However, when I test for swipe in CrimeListFragment.onItemListClick method, it never detects the swipe. This made me less happy :frowning:

I’m a very old programmer who cut his teeth on assembler and C and I still struggle a bit with these new-fangled OO languages, so it could be that my approach here is just wrong so I’d really appreciate some help.

Here’s the complete code for CrimeListFragment - all other files are unchanged from the end of Chapter 10):

package uk.org.wookey.android.criminalintent;

import java.util.ArrayList;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class CrimeListFragment extends ListFragment {
	private final static String TAG = "CrimeListFragment";
	
	private ArrayList<Crime> mCrimes;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getActivity().setTitle(R.string.crimes_title);
		mCrimes = CrimeLab.get(getActivity()).getCrimes();
		
		CrimeAdapter adapter = new CrimeAdapter(mCrimes);
		
		Log.d(TAG, "Create CrimeListFragment");
		
		setListAdapter(adapter);
	}
	
	@Override
	public void onResume() {
		super.onResume();
		((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
	}
	
	@Override
	public void onListItemClick(ListView l, View v, int position, long id) {
		Log.d(TAG, "Click()");
		CrimeAdapter adapter = (CrimeAdapter) getListAdapter();
		
		Crime c = adapter.getItem(position);
		
		// Start CrimeActivity
		if (adapter.swipeDetected() && (adapter.getAction() == CrimeAdapter.SWIPE_LR)) {
			Toast mytoast=new Toast(v.getContext());
			mytoast.setView(v);
			mytoast.setDuration(Toast.LENGTH_LONG);
			mytoast.setText("Well swipe me!");
			mytoast.show();
		}
		else {
			Intent i = new Intent(getActivity(), CrimeActivity.class);
			i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());
			startActivity(i);
		}
	}
	
	private class CrimeAdapter extends ArrayAdapter<Crime> implements OnTouchListener {
		private final static String TAG = "CrimeAdapter";
		
		public final static int SWIPE_NONE = 0;
		public final static int SWIPE_LR = 1;
		public final static int SWIPE_RL = 2;

		private final static int MIN_DISTANCE = 100;
		private float mDownX;
		private int mSwipeDirection;
		
		public CrimeAdapter(ArrayList<Crime> crimes) {
			super(getActivity(), android.R.layout.simple_list_item_1, crimes);
		}
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			if (convertView == null) {
				convertView = getActivity().getLayoutInflater()
						.inflate(R.layout.list_item_crime,  null);
				
				convertView.setOnTouchListener(this);
			}
			
			Crime c = getItem(position);
			
			TextView titleTextView = (TextView)convertView.findViewById(R.id.crime_list_item_titleTextView);
			titleTextView.setText(c.getTitle());
			
			TextView dateTextView = (TextView)convertView.findViewById(R.id.crime_list_item_dateTextView);
			dateTextView.setText(c.getDate().toString());
			
			CheckBox solvedCheckBox = (CheckBox)convertView.findViewById(R.id.crime_list_item_solvedCheckBox);
			solvedCheckBox.setChecked(c.isSolved());
			
			return convertView;
		}
		
		public boolean swipeDetected() {
	        return mSwipeDirection != SWIPE_NONE;
	    }

	    public int getAction() {
	        return mSwipeDirection;
	    }
	    
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			//Log.d(TAG, "onTouch(), action=" + event.getAction());
			
	        switch (event.getAction()) {
	        case MotionEvent.ACTION_DOWN:
	            mDownX = event.getX();
	            mSwipeDirection = SWIPE_NONE;
	            Log.d(TAG, "Down");
	            return true;
	        
	        case MotionEvent.ACTION_UP:
	            float deltaX = mDownX - event.getX();
	            Log.d(TAG, "Up - deltaX=" + deltaX);
	            if (Math.abs(deltaX) > MIN_DISTANCE) {
	            	// left or right?
	            	if (deltaX > 0) {
	            		mSwipeDirection = SWIPE_RL;
	            		Log.d(TAG, "RL Swipe");
	            	}
	            	else {
	            		mSwipeDirection = SWIPE_LR;
	            		Log.d(TAG, "LR Swipe");
	            	}
	            	return true;
	            }
	        }
	        
	        Log.d(TAG, "onTouch() -> false");
			return false;
		}
	}
}

Any pointers gratefully received.

Thanks,
-Bob