smooth article swiping using viewpager (in online mode)

This commit is contained in:
Andrew Dolgov 2011-12-09 23:49:55 +03:00
parent ff598602bd
commit 74c837e89f
8 changed files with 155 additions and 190 deletions

View File

@ -42,13 +42,6 @@
android:layout_weight="0" android:layout_weight="0"
android:layout_gravity="center_vertical" > android:layout_gravity="center_vertical" >
<ImageView
android:id="@+id/prev_article"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:src="@drawable/ic_prev_article" />
<LinearLayout <LinearLayout
android:paddingLeft="5dp" android:paddingLeft="5dp"
android:paddingRight="5dp" android:paddingRight="5dp"
@ -96,14 +89,6 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<ImageView
android:id="@+id/next_article"
android:layout_width="wrap_content"
android:clickable="true"
android:layout_height="wrap_content"
android:layout_weight="0"
android:src="@drawable/ic_next_article" />
</LinearLayout> </LinearLayout>
<ImageView <ImageView

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/article_pager">
</android.support.v4.view.ViewPager>

View File

@ -31,16 +31,26 @@ import android.widget.TextView;
import com.google.ads.AdRequest; import com.google.ads.AdRequest;
import com.google.ads.AdView; import com.google.ads.AdView;
public class ArticleFragment extends Fragment implements OnClickListener { public class ArticleFragment extends Fragment {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String TAG = this.getClass().getSimpleName(); private final String TAG = this.getClass().getSimpleName();
private SharedPreferences m_prefs; private SharedPreferences m_prefs;
private Article m_article; private Article m_article;
private OnlineServices m_onlineServices; private OnlineServices m_onlineServices;
private Article m_nextArticle; //private Article m_nextArticle;
private Article m_prevArticle; //private Article m_prevArticle;
private GestureDetector m_gestureDetector;
public ArticleFragment() {
super();
}
public ArticleFragment(Article article) {
super();
m_article = article;
}
private View.OnTouchListener m_gestureListener; private View.OnTouchListener m_gestureListener;
@Override @Override
@ -52,17 +62,6 @@ public class ArticleFragment extends Fragment implements OnClickListener {
View view = inflater.inflate(R.layout.article_fragment, container, false); View view = inflater.inflate(R.layout.article_fragment, container, false);
m_gestureDetector = new GestureDetector(new MyGestureDetector());
m_gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent aEvent) {
if (m_gestureDetector.onTouchEvent(aEvent))
return true;
else
return false;
}
};
Activity activity = (Activity)getActivity(); Activity activity = (Activity)getActivity();
if (activity != null) { if (activity != null) {
@ -192,26 +191,6 @@ public class ArticleFragment extends Fragment implements OnClickListener {
} }
} }
ImageView next = (ImageView)view.findViewById(R.id.next_article);
if (next != null) {
if (m_nextArticle != null) {
next.setOnClickListener(this);
} else {
next.setImageResource(R.drawable.ic_next_article_disabled);
}
}
ImageView prev = (ImageView)view.findViewById(R.id.prev_article);
if (prev != null) {
if (m_prevArticle != null) {
prev.setOnClickListener(this);
} else {
prev.setImageResource(R.drawable.ic_prev_article_disabled);
}
}
} }
return view; return view;
@ -229,65 +208,14 @@ public class ArticleFragment extends Fragment implements OnClickListener {
out.putParcelable("article", m_article); out.putParcelable("article", m_article);
} }
@Override @Override
public void onAttach(Activity activity) { public void onAttach(Activity activity) {
super.onAttach(activity); super.onAttach(activity);
m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
m_onlineServices = (OnlineServices)activity; m_onlineServices = (OnlineServices)activity;
m_article = m_onlineServices.getSelectedArticle(); //m_article = m_onlineServices.getSelectedArticle();
m_prevArticle = m_onlineServices.getRelativeArticle(m_article, RelativeArticle.BEFORE);
m_nextArticle = m_onlineServices.getRelativeArticle(m_article, RelativeArticle.AFTER);
} }
@Override
public void onClick(View v) {
if (v.getId() == R.id.next_article) {
m_onlineServices.openArticle(m_nextArticle, 0);
} else if (v.getId() == R.id.prev_article) {
m_onlineServices.openArticle(m_prevArticle, R.anim.slide_right);
}
}
// http://blog.blackmoonit.com/2010/07/gesture-detection-swipe-detection_4292.html
class MyGestureDetector extends SimpleOnGestureListener {
private static final int SWIPE_MIN_DISTANCE = 100;
private static final int SWIPE_MAX_OFF_PATH = 100;
private static final int SWIPE_THRESHOLD_VELOCITY = 100;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float dX = e2.getX()-e1.getX();
float dY = e1.getY()-e2.getY();
if (Math.abs(dY)<SWIPE_MAX_OFF_PATH &&
Math.abs(velocityX)>=SWIPE_THRESHOLD_VELOCITY &&
Math.abs(dX)>=SWIPE_MIN_DISTANCE ) {
if (dX>0) {
//Log.d(TAG, "Right swipe");
if (m_prevArticle != null)
m_onlineServices.openArticle(m_prevArticle, R.anim.slide_right);
} else {
//Log.d(TAG, "Left swipe");
if (m_nextArticle != null)
m_onlineServices.openArticle(m_nextArticle, 0);
}
return true;
/* } else if (Math.abs(dX)<SWIPE_MAX_OFF_PATH &&
Math.abs(velocityY)>=SWIPE_THRESHOLD_VELOCITY &&
Math.abs(dY)>=SWIPE_MIN_DISTANCE ) {
if (dY>0) {
Log.d(TAG, "Up swipe");
} else {
Log.d(TAG, "Down swipe");
}
return true; */
}
return false;
}
};
} }

View File

@ -0,0 +1,100 @@
package org.fox.ttrss;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ArticlePager extends Fragment {
private PagerAdapter m_adapter;
private OnlineServices m_onlineServices;
private HeadlinesFragment m_hf;
private Article m_article;
private class PagerAdapter extends FragmentStatePagerAdapter {
public PagerAdapter(FragmentManager fm, Article article) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Article article = m_hf.getArticleAtPosition(position);
if (article != null) {
ArticleFragment af = new ArticleFragment(article);
return af;
}
return null;
}
@Override
public int getCount() {
return m_hf.getAllArticles().size();
}
}
public ArticlePager() {
super();
}
public ArticlePager(Article article) {
super();
m_article = article;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.article_pager, container, false);
m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager(), m_onlineServices.getSelectedArticle());
ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager);
HeadlinesFragment hf = (HeadlinesFragment)getActivity().getSupportFragmentManager().findFragmentById(R.id.headlines_fragment);
int position = hf.getArticlePosition(m_article);
pager.setAdapter(m_adapter);
pager.setCurrentItem(position);
pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int position) {
Article article = m_hf.getArticleAtPosition(position);
if (article != null) {
article.unread = false;
m_onlineServices.setSelectedArticle(article);
m_onlineServices.saveArticleUnread(article);
}
}
});
return view;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
m_hf = (HeadlinesFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.headlines_fragment);
m_onlineServices = (OnlineServices)activity;
}
}

View File

@ -479,6 +479,11 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
public void notifyUpdated() { public void notifyUpdated() {
m_adapter.notifyDataSetChanged(); m_adapter.notifyDataSetChanged();
Article article = m_onlineServices.getSelectedArticle();
if (article != null) {
setActiveArticleId(article.id);
}
} }
public ArticleList getAllArticles() { public ArticleList getAllArticles() {
@ -547,5 +552,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener,
return m_activeArticleId; return m_activeArticleId;
} }
public int getArticlePosition(Article article) {
return m_adapter.getPosition(article);
}
} }

View File

@ -23,6 +23,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.util.Log; import android.util.Log;
@ -1389,7 +1390,13 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
findViewById(R.id.article_fragment).setVisibility(View.VISIBLE); findViewById(R.id.article_fragment).setVisibility(View.VISIBLE);
} }
ArticleFragment frag = new ArticleFragment(); Fragment frag;
if (m_smallScreenMode) {
frag = new ArticlePager(article);
} else {
frag = new ArticleFragment(article);
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.article_fragment, frag); ft.replace(R.id.article_fragment, frag);
@ -1717,4 +1724,10 @@ public class MainActivity extends FragmentActivity implements OnlineServices {
viewCategory(cat, browse && cat.id >= 0); viewCategory(cat, browse && cat.id >= 0);
} }
@Override
public void setSelectedArticle(Article article) {
m_selectedArticle = article;
updateHeadlines();
}
} }

View File

@ -33,7 +33,7 @@ import android.widget.TextView;
import com.google.ads.AdView; import com.google.ads.AdView;
public class OfflineArticleFragment extends Fragment implements OnClickListener { public class OfflineArticleFragment extends Fragment {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String TAG = this.getClass().getSimpleName(); private final String TAG = this.getClass().getSimpleName();
@ -41,8 +41,7 @@ public class OfflineArticleFragment extends Fragment implements OnClickListener
private int m_articleId; private int m_articleId;
private int m_nextArticleId; private int m_nextArticleId;
private int m_prevArticleId; private int m_prevArticleId;
private GestureDetector m_gestureDetector;
private View.OnTouchListener m_gestureListener;
private Cursor m_cursor; private Cursor m_cursor;
private OfflineServices m_offlineServices; private OfflineServices m_offlineServices;
@ -57,16 +56,6 @@ public class OfflineArticleFragment extends Fragment implements OnClickListener
View view = inflater.inflate(R.layout.article_fragment, container, false); View view = inflater.inflate(R.layout.article_fragment, container, false);
m_gestureDetector = new GestureDetector(new MyGestureDetector());
m_gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent aEvent) {
if (m_gestureDetector.onTouchEvent(aEvent))
return true;
else
return false;
}
};
// TODO change to interface? // TODO change to interface?
Activity activity = getActivity(); Activity activity = getActivity();
@ -174,8 +163,7 @@ public class OfflineArticleFragment extends Fragment implements OnClickListener
e.printStackTrace(); e.printStackTrace();
} }
if (m_offlineServices.isSmallScreen())
web.setOnTouchListener(m_gestureListener);
} }
TextView dv = (TextView)view.findViewById(R.id.date); TextView dv = (TextView)view.findViewById(R.id.date);
@ -199,26 +187,6 @@ public class OfflineArticleFragment extends Fragment implements OnClickListener
av.setVisibility(View.GONE); av.setVisibility(View.GONE);
} }
ImageView next = (ImageView)view.findViewById(R.id.next_article);
if (next != null) {
if (m_nextArticleId != 0) {
next.setOnClickListener(this);
} else {
next.setImageResource(R.drawable.ic_next_article_disabled);
}
}
ImageView prev = (ImageView)view.findViewById(R.id.prev_article);
if (prev != null) {
if (m_prevArticleId != 0) {
prev.setOnClickListener(this);
} else {
prev.setImageResource(R.drawable.ic_prev_article_disabled);
}
}
} }
return view; return view;
@ -255,53 +223,5 @@ public class OfflineArticleFragment extends Fragment implements OnClickListener
m_nextArticleId = m_offlineServices.getRelativeArticleId(m_articleId, m_offlineServices.getActiveFeedId(), RelativeArticle.AFTER); m_nextArticleId = m_offlineServices.getRelativeArticleId(m_articleId, m_offlineServices.getActiveFeedId(), RelativeArticle.AFTER);
} }
@Override
public void onClick(View v) {
if (v.getId() == R.id.next_article) {
m_offlineServices.openArticle(m_nextArticleId, 0);
} else if (v.getId() == R.id.prev_article) {
m_offlineServices.openArticle(m_prevArticleId, R.anim.slide_right);
}
}
// http://blog.blackmoonit.com/2010/07/gesture-detection-swipe-detection_4292.html
class MyGestureDetector extends SimpleOnGestureListener {
private static final int SWIPE_MIN_DISTANCE = 100;
private static final int SWIPE_MAX_OFF_PATH = 100;
private static final int SWIPE_THRESHOLD_VELOCITY = 100;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
float dX = e2.getX()-e1.getX();
float dY = e1.getY()-e2.getY();
if (Math.abs(dY)<SWIPE_MAX_OFF_PATH &&
Math.abs(velocityX)>=SWIPE_THRESHOLD_VELOCITY &&
Math.abs(dX)>=SWIPE_MIN_DISTANCE ) {
if (dX>0) {
//Log.d(TAG, "Right swipe");
if (m_prevArticleId != 0)
m_offlineServices.openArticle(m_prevArticleId, 0);
} else {
//Log.d(TAG, "Left swipe");
if (m_nextArticleId != 0)
m_offlineServices.openArticle(m_nextArticleId, 0);
}
return true;
/* } else if (Math.abs(dX)<SWIPE_MAX_OFF_PATH &&
Math.abs(velocityY)>=SWIPE_THRESHOLD_VELOCITY &&
Math.abs(dY)>=SWIPE_MIN_DISTANCE ) {
if (dY>0) {
Log.d(TAG, "Up swipe");
} else {
Log.d(TAG, "Down swipe");
}
return true; */
}
return false;
}
};
} }

View File

@ -24,5 +24,6 @@ public interface OnlineServices {
public boolean getUnreadOnly(); public boolean getUnreadOnly();
public boolean getLicensed(); public boolean getLicensed();
public int getApiLevel(); public int getApiLevel();
public void setSelectedArticle(Article article);
} }