I have a HorizontalScrollView as an item of ListView. There is clickable image in each HorizontalScrollView. Also Horizontal scroll view should have specific behavior of scrolling. I have already implemented it for single HorizontalScrollView. But now I need to make a List of these scroll views and each of them should have this behavior. I'm using ParseQueryAdapter, because I get information from parse.com. When I tried to use the code for specific scroll on each item, only the last item had this behavior. And laso it worked quite bad. But maybe it's my fault. Please help me to set the onTouchListener for each item. And the onClickListener for each ImageView in each item. This is my code
public class CustomParseQueryAdapter extends ParseQueryAdapter<Lighter> {
Activity activity;
int rankNumber;
Bitmap bitmap;
int currentScrollViewPosition;
int middlePosition;
HorizontalScrollView itemScrollView;
RelativeLayout rankParentLayout;
RelativeLayout lighterNameAndMilesLayout;
GestureDetector gestureDetector;
public CustomParseQueryAdapter(Context context){
super(context, new QueryFactory<Lighter>() {
@Override
public ParseQuery<Lighter> create() {
ParseQuery<Lighter> query = new ParseQuery<>("Lighter");
query.orderByDescending("miles");
query.include("master");
return query;
}
});
activity = (Activity) context;
rankNumber = 1;
}
@Override
public View getItemView(Lighter lighter, View v, ViewGroup parent) {
if (v == null){
v = View.inflate(getContext(), R.layout.ranking_list_item, null);
}
super.getItemView(lighter, v, parent);
gestureDetector = new GestureDetector(new CustomGestureDetector());
itemScrollView = (HorizontalScrollView) v.findViewById(R.id.item_scroll_view);
LinearLayout itemParentLayout = (LinearLayout) v.findViewById(R.id.rank_item_linear_scroll_view);
RelativeLayout crossedCitiesParentLayout = (RelativeLayout) v.findViewById(R.id.item_crossed_cities_layout);
RelativeLayout timesCheckedParentLayout = (RelativeLayout) v.findViewById(R.id.item_times_checked_layout);
rankParentLayout = (RelativeLayout) v.findViewById(R.id.item_rank_layout);
lighterNameAndMilesLayout = (RelativeLayout) v.findViewById(R.id.item_lighter_name_and_miles_layout);
TextView crossedCitiesAmount = (TextView) v.findViewById(R.id.item_crossed_cities);
TextView timesCheckedAmount = (TextView) v.findViewById(R.id.item_times_checked);
TextView itemRankNumber = (TextView) v.findViewById(R.id.item_rank_number);
ImageView lighterImage = (ImageView) v.findViewById(R.id.item_lighter_image);
TextView lighterName = (TextView) v.findViewById(R.id.item_lighter_name);
TextView milesTravelled = (TextView) v.findViewById(R.id.item_lighter_miles_travelled);
// This userImage ImageView should have the onClickListener to start another fragment
ImageView userImage = (ImageView) v.findViewById(R.id.item_user_image);
String lighterColor = lighter.getColor();
itemParentLayout.setBackgroundColor(FragmentMap.getColor(lighterColor, activity.getResources()));
crossedCitiesParentLayout.setBackgroundColor(FragmentMap.getAnotherColor(lighterColor, activity.getResources()));
timesCheckedParentLayout.setBackgroundColor(FragmentMap.getAnotherColor(lighterColor, activity.getResources()));
rankParentLayout.setBackgroundColor(FragmentMap.getAnotherColor(lighterColor, activity.getResources()));
lighterNameAndMilesLayout.getLayoutParams().width = FragmentMap.getScreenSize(activity).x - FragmentMap.MARGIN;
crossedCitiesAmount.setText(lighter.getCitiesAmount() + " CITIES");
timesCheckedAmount.setText(lighter.getTimesChecked() + " TIMES");
itemRankNumber.setText(String.valueOf(rankNumber));
rankNumber++;
setUpLighterImage(lighterImage, lighterColor);
lighterName.setText(lighter.getLighterName().toUpperCase());
milesTravelled.setText(lighter.getIntMiles() + " MILES TRAVELLED");
final ParseUser lighterMasterUser = lighter.getParseUser("master");
final String userProfileID = lighterMasterUser.getString("profileID");
Thread thread = new Thread(new Runnable() {
public void run() {
bitmap = FragmentMap.getBitmap(userProfileID, activity);
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
userImage.setImageBitmap(FragmentMap.getBitmapWithTineCircle(bitmap, activity));
middlePosition = rankParentLayout.getBottom() - FragmentMap.MARGIN;
v.post(new Runnable() {
@Override
public void run() {
itemScrollView.scrollTo(middlePosition, 0);
currentScrollViewPosition = 0;
}
});
itemScrollView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
});
return v;
}
private void setUpLighterImage(ImageView view, String color){
switch (color){
case "red":
view.setImageResource(R.drawable.red);
break;
case "pink":
view.setImageResource(R.drawable.pink);
break;
case "green":
view.setImageResource(R.drawable.green);
break;
case "orange":
view.setImageResource(R.drawable.orange);
break;
case "yellow":
view.setImageResource(R.drawable.yellow);
break;
case "silver":
view.setImageResource(R.drawable.silver);
break;
// it is gold, but was light brown
case "gold":
view.setImageResource(R.drawable.gold);
break;
case "copper":
view.setImageResource(R.drawable.copper);
break;
}
}
class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (e1.getX() < e2.getX()) {
getScrollPosition("left");
} else {
getScrollPosition("right");
}
// mapTitleScrollView.smoothScrollTo(scrollPosition, 0);
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY){
return true;
}
}
private void getScrollPosition(String direction){
switch (direction){
case "left":
if (currentScrollViewPosition == 1){ // if scrollview is in rightmost position move to center
toCenterPosition();
} else if (currentScrollViewPosition == 0){ // if scrollview is in center position move left
toLeftPosition();
}
break;
case "right":
if (currentScrollViewPosition == -1){ // if scrollview is in leftmost position move to center
toCenterPosition();
} else if (currentScrollViewPosition == 0){ // if scrollview is in center position move right
toRightPosition();
}
break;
}
}
private void toLeftPosition(){
currentScrollViewPosition = -1;
itemScrollView.fullScroll(HorizontalScrollView.FOCUS_LEFT);
}
private void toRightPosition(){
currentScrollViewPosition = 1;
itemScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
private void toCenterPosition(){
currentScrollViewPosition = 0;
itemScrollView.smoothScrollTo(middlePosition, 0);
}
}
This is my ListView fragment code
public class FragmentList extends ListFragment {
ApplicationInterface fragmentHolder;
CustomParseQueryAdapter mainAdapter;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
fragmentHolder = (ApplicationInterface) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString());
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_list, container, false);
mainAdapter = new CustomParseQueryAdapter(getActivity());
setListAdapter(mainAdapter);
return view;
}
}
And XML for ListView:
<ListView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
Also I need onClickListener on whole item of the list view. But I think it should be implemented in my FragmentList
class
Ok, so if anyone is interested in my solution, here it is: The reason why my gesture detector was working only on the last item of the list view is the global variable for storing HorizontalScrollView. I made it local and passed it as a parameter to my gesture detector. Also I have changed the onFling method detection, because it has conflicts with onClick listener. It trhows the NullPointerException, telling me that I'm trying to use method MotionEvent.getX() on a null object. This is how my code looks now:
public class CustomParseQueryAdapter extends ParseQueryAdapter<Lighter> {
Activity activity;
int rankNumber;
Bitmap bitmap;
int currentScrollViewPosition;
ApplicationInterface fragmentHolder;
public CustomParseQueryAdapter(Context context, ApplicationInterface fragmentHolder){
super(context, new QueryFactory<Lighter>() {
@Override
public ParseQuery<Lighter> create() {
ParseQuery<Lighter> query = new ParseQuery<>("Lighter");
query.orderByDescending("miles");
query.include("master");
return query;
}
});
activity = (Activity) context;
rankNumber = 1;
this.fragmentHolder = fragmentHolder;
}
@Override
public View getItemView(final Lighter lighter, View v, ViewGroup parent) {
if (v == null){
v = View.inflate(getContext(), R.layout.ranking_list_item, null);
}
final HorizontalScrollView itemScrollView = (HorizontalScrollView) v.findViewById(R.id.item_scroll_view);
itemScrollView.setSmoothScrollingEnabled(true);
v.post(new Runnable() {
@Override
public void run() {
itemScrollView.fullScroll(View.FOCUS_RIGHT);
currentScrollViewPosition = 1;
}
});
LinearLayout itemParentLayout = (LinearLayout) v.findViewById(R.id.rank_item_linear_scroll_view);
RelativeLayout crossedCitiesParentLayout = (RelativeLayout) v.findViewById(R.id.item_crossed_cities_layout);
RelativeLayout timesCheckedParentLayout = (RelativeLayout) v.findViewById(R.id.item_times_checked_layout);
RelativeLayout rankParentLayout = (RelativeLayout) v.findViewById(R.id.item_rank_layout);
RelativeLayout lighterNameAndMilesLayout = (RelativeLayout) v.findViewById(R.id.item_lighter_name_and_miles_layout);
TextView crossedCitiesAmount = (TextView) v.findViewById(R.id.item_crossed_cities);
TextView timesCheckedAmount = (TextView) v.findViewById(R.id.item_times_checked);
TextView itemRankNumber = (TextView) v.findViewById(R.id.item_rank_number);
ImageView lighterImage = (ImageView) v.findViewById(R.id.item_lighter_image);
TextView lighterName = (TextView) v.findViewById(R.id.item_lighter_name);
TextView milesTravelled = (TextView) v.findViewById(R.id.item_lighter_miles_travelled);
ImageView userImage = (ImageView) v.findViewById(R.id.item_user_image);
final String lighterColor = lighter.getColor();
final String lighterObjectId = lighter.getObjectId();
itemParentLayout.setBackgroundColor(FragmentMap.getColor(lighterColor, activity.getResources()));
crossedCitiesParentLayout.setBackgroundColor(FragmentMap.getColor(lighterColor, activity.getResources()));
timesCheckedParentLayout.setBackgroundColor(FragmentMap.getAnotherColor(lighterColor, activity.getResources()));
rankParentLayout.setBackgroundColor(FragmentMap.getAnotherColor(lighterColor, activity.getResources()));
lighterNameAndMilesLayout.getLayoutParams().width = FragmentMap.getScreenSize(activity).x - FragmentMap.MARGIN;
crossedCitiesAmount.setText(lighter.getCitiesAmount() + " CITIES");
timesCheckedAmount.setText(lighter.getTimesChecked() + " TIMES");
itemRankNumber.setText("#" + String.valueOf(rankNumber));
rankNumber++;
setUpLighterImage(lighterImage, lighterColor);
lighterName.setText(lighter.getLighterName().toUpperCase());
milesTravelled.setText(lighter.getIntMiles() + " MILES TRAVELLED");
final ParseUser lighterMasterUser = lighter.getParseUser("master");
final String userProfileID = lighterMasterUser.getString("profileID");
Thread thread = new Thread(new Runnable() {
public void run() {
bitmap = FragmentMap.getBitmap(userProfileID, activity);
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
userImage.setImageBitmap(FragmentMap.getBitmapWithTineCircle(bitmap, activity));
final GestureDetector gestureDetector = new GestureDetector(
new CustomGestureDetector(currentScrollViewPosition, itemScrollView));
lighterNameAndMilesLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fragmentHolder.onMapRedirect(lighterObjectId, lighterColor);
}
});
itemScrollView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
});
super.getItemView(lighter, v, parent);
return v;
}
private void setUpLighterImage(ImageView view, String color){
switch (color){
case "red":
view.setImageResource(R.drawable.red);
break;
case "pink":
view.setImageResource(R.drawable.pink);
break;
case "green":
view.setImageResource(R.drawable.green);
break;
case "orange":
view.setImageResource(R.drawable.orange);
break;
case "yellow":
view.setImageResource(R.drawable.yellow);
break;
case "silver":
view.setImageResource(R.drawable.silver);
break;
// it is gold, but was light brown
case "gold":
view.setImageResource(R.drawable.gold);
break;
case "copper":
view.setImageResource(R.drawable.copper);
break;
}
}
class CustomGestureDetector extends GestureDetector.SimpleOnGestureListener {
int currentScrollViewPosition;
HorizontalScrollView itemScrollView;
public CustomGestureDetector(int currentPosition, HorizontalScrollView scrollView){
currentScrollViewPosition = currentPosition;
itemScrollView = scrollView;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
if (velocityX > 0){
getScrollPosition("left");
} else {
getScrollPosition("right");
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY){
if (distanceX < 0){
getScrollPosition("left");
} else {
getScrollPosition("right");
}
return true;
}
private void getScrollPosition(String direction){
switch (direction){
case "left":
if (currentScrollViewPosition == 1){
toLeftPosition();
} else if (currentScrollViewPosition == 0){
toLeftPosition();
}
break;
case "right":
if (currentScrollViewPosition == -1){
toRightPosition();
} else if (currentScrollViewPosition == 0){
toRightPosition();
}
break;
}
}
private void toLeftPosition(){
currentScrollViewPosition = -1;
itemScrollView.fullScroll(HorizontalScrollView.FOCUS_LEFT);
}
private void toRightPosition(){
currentScrollViewPosition = 1;
itemScrollView.fullScroll(HorizontalScrollView.FOCUS_RIGHT);
}
}
}