像Pinterest或Tumblr一样向后滑动

有人有一个想法如何Pinterest或Tumblr在那里实施“刷卡”的方法。

即在Pinterest上,您可以点击新闻提要上的post。 比DetailActivity启动并显示所选文章的详细信息。 您可以按返回button返回到新闻馈送活动,也可以向左滑动(详细信息活动)返回到新闻馈送活动。

video:http: //youtu.be/eVcSCWetnTA

通常我会使用overridePendingTransition() ,但overridePendingTransition()需要animation(资源ID像R.anim.foo )。 Pinterest和Tumblr只有在用户做滑动手势时才开始animation。 他们也支持某种“逐帧animation”的手指移动。 因此,他们追踪手指移动的距离,并animation转换到相应的百分比值。

我知道如何使用带有FragmentTransaction的“真正的java”Animation / AnimatorSet Object来animation片段replace。 有片段,我必须重写onCreateAnimator() ,但我不知道如何实现像这样的活动。 是否有一个onCreateAnimator() (或类似的)的活动? 也不知道如何刷卡的行为,因为它现在不开始animation,但更多的一步一步的属性改变的窗口/活动/片段或任何…

有什么build议么?

编辑:我已经find了YouTube上pinterest应用程序的video:http: //youtu.be/eVcSCWetnTA这就是我想要实现的。

我估计Pinterest正在使用Fragments和onCreateAnimator()来实现“向后滑动”。 由于我的应用程序已经在一个活动中有片段和ChildFragments,所以如果我可以为活动实现这个function,那么这对我来说会容易得多。

再一次:我知道如何检测轻扫手势,这不是我所要求的。 观看YouTubevideo:http: //youtu.be/eVcSCWetnTA


更新:我已经创build了一个小的库,它不像Pinterest或Tumblrs实现完全相同的行为,但是对于我的应用程序,这似乎是一个很好的解决scheme: https : //github.com/sockeqwe/SwipeBack? source = c

看来你正在寻找的效果是android开发人员的网站ViewPager的样本之一。

深度页面转换器部分查看http://developer.android.com/training/animation/screen-slide.html#depth-page 。 它有一个video和源代码。

使用ViewPager.PageTransformer,您可以决定从一个切换到另一个时页面的行为。

样本和你链接的video的唯一区别是左右似乎是倒置的,但是对于我在问题中链接的YouTubevideo中看到的内容应该是一个很好的起点。 这两个意见的行动将不得不交换。 如这段代码所示( mPager.setPageTransformer的第一个参数应该是reverseDrawingOrder = false)。 注意中间的2, if切换部分, positionvariables处理与切换边稍有不同。 有弹性的效果是作为一个练习。 请分享,当你得到的!

  package com.example.android.animationsdemo; import android.support.v4.view.ViewPager; import android.view.View; public class SinkPageTransformer implements ViewPager.PageTransformer { private static float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 0) { // [-1,0] // Fade the page out. view.setAlpha(1 + position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else if (position <= 1) { // (0,1] // Use the default slide transition when moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } } 

以防万一与示例页面噗,这是该部分的原始代码:

  public class DepthPageTransformer implements ViewPager.PageTransformer { private static float MIN_SCALE = 0.75f; public void transformPage(View view, float position) { int pageWidth = view.getWidth(); if (position < -1) { // [-Infinity,-1) // This page is way off-screen to the left. view.setAlpha(0); } else if (position <= 0) { // [-1,0] // Use the default slide transition when moving to the left page view.setAlpha(1); view.setTranslationX(0); view.setScaleX(1); view.setScaleY(1); } else if (position <= 1) { // (0,1] // Fade the page out. view.setAlpha(1 - position); // Counteract the default slide transition view.setTranslationX(pageWidth * -position); // Scale the page down (between MIN_SCALE and 1) float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)); view.setScaleX(scaleFactor); view.setScaleY(scaleFactor); } else { // (1,+Infinity] // This page is way off-screen to the right. view.setAlpha(0); } } } 

更新:修复了这个项目的内存使用问题,并将幻灯片样式更改为iOS。

在这里输入图像说明

我写了一个像Pinterest和tumblr一样的演示,你只需扩展BaseActivity,你就可以得到一个轻扫效果,工作顺利!

检查这个: https : //github.com/chenjishi/SlideActivity

和截图: 在这里输入图像说明

我发现了一个基于SwipeBack(像Pinterest)的GitHub项目。

这是一个很好的开源项目,应该可以解决你的问题。 它可以根据需要进行操作,例如按回或简单滑动即可转到上一个屏幕。 作为这个项目有select权

1.从左向右滑动

2.从右向左滑动

3.轻扫底部到顶部

https://github.com/Issacw0ng/SwipeBackLayout

还可以从Google Play安装此演示应用程序。

https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo

附加屏幕截图: –

在这里输入图像说明

希望这会帮助你。

我能在15分钟内做到这一点,这是一个不错的开始。 如果你花一些时间,你可能会优化它。

 package mobi.sherif.activitydrag; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; import android.view.animation.LinearInterpolator; import android.view.animation.TranslateAnimation; import android.widget.FrameLayout.LayoutParams; public class MainActivity extends Activity { private static final double PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH = 0.3; View mView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mView = LayoutInflater.from(this).inflate(R.layout.activity_main, null); setContentView(mView); } private boolean isDragging = false; int startX; int currentX; @Override public boolean onTouchEvent(MotionEvent event) { Log.v("sherif", isDragging?"YES":"NO" + ": " + event.getX()); if(!isDragging) { if(event.getAction() == MotionEvent.ACTION_DOWN && event.getX()<24) { isDragging = true; startX = (int) event.getX(); currentX = 0; return true; } return super.onTouchEvent(event); } switch(event.getAction()) { case MotionEvent.ACTION_MOVE: currentX = (int) event.getX() - startX; LayoutParams params = (LayoutParams) mView.getLayoutParams(); params.leftMargin = currentX; params.rightMargin = -1 * currentX; mView.requestLayout(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: isDragging = false; double currentPercent1 = (double) currentX / mView.getWidth(); float currentPercent = (float) currentPercent1; if(currentX > PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH * mView.getWidth()) { AnimationSet animation = new AnimationSet(false); Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f - currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); anim.setInterpolator(new LinearInterpolator()); anim.setStartTime(AnimationUtils.currentAnimationTimeMillis()); animation.addAnimation(anim); anim = new AlphaAnimation(1.0f, 0.5f); anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime)); anim.setInterpolator(new LinearInterpolator()); anim.setStartTime(AnimationUtils.currentAnimationTimeMillis()); animation.addAnimation(anim); animation.setFillAfter(true); animation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { finish(); } }); mView.startAnimation(animation); } else { AnimationSet animation = new AnimationSet(false); Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f -1 * currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f); anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime)); anim.setInterpolator(new LinearInterpolator()); anim.setStartTime(AnimationUtils.currentAnimationTimeMillis()); animation.addAnimation(anim); animation.setFillAfter(true); animation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) {} @Override public void onAnimationRepeat(Animation animation) {} @Override public void onAnimationEnd(Animation animation) { LayoutParams params = (LayoutParams) mView.getLayoutParams(); params.leftMargin = 0; params.rightMargin = 0; mView.requestLayout(); mView.clearAnimation(); } }); mView.startAnimation(animation); } break; } return true; } } 

我只是检查层次结构查看器。 看起来他们正在使用ViewPager和上一个活动的屏幕截图。

我会build议做以下事情:

首先检测用户在设备中做的手势。 你可以参考这个链接

我不打算从上面的链接中复制相关的代码,因为我相信这是被接受的答案

其次,你可以在这个方法

 public void onSwipeLeft() { Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show(); } 

按照这个问题的build议做下面的事情

他们在那里谈论用animation完成一项活动

 Look into doing it through a theme. You can define enter exit animations for activities or the entire application 

希望这可以帮助你

所以我想我自己find了解决scheme:

首先:Pinterest确实使用了一个带有自定义页面变换器的ViewPager,比如@frozenkoi在他的回答中提到过。 您可以在pinterest应用程序中看到查看传呼机的超额边缘效应。

@Amit Gupta指出图书馆让活动滑了下来。 它像各种导航抽屉一样的概念,也设置了半透明的主题。 他们滑动布局。 但那不是我正在寻找的,因为它将顶级活动向右滑动,而不是简单地调用finish()。 但是下面的活动不会被animation化。

解决方法是(我想这是Tumblr做的)用animation对象编写你自己的animation,并一步一步地animation。 这可以通过ActivityOptions完成。 在我看来,这将是解决scheme。

我写了一个项目。 它可以让你开发一个由Fragments轻松导航的应用程序,就像Pinterest一样执行。

https://github.com/fengdai/FragmentMaster

也许这不是你想要的答案。 但我希望对别人有用。

我正在处理这个我目前正在研究的项目,并提出了以下代码。 也许这与你无关,但它可以帮助这个职位的新人。 🙂

基本上它是你在答案中提到的ViewPager实现,但是我认为这是对你的问题最简单和最快捷的解决scheme。 缺点是它只适用于碎片(可以很容易地改变为对象),如果你想添加ActionBar到滑动,你可能最终创build一个自定义的。

 public class DoubleViewPager extends FrameLayout implements ViewPager.OnPageChangeListener { /** * Represents number of objects in DelegateViewPager. In others words it stands for one main content * window and one content detail window */ private static final int SCREEN_COUNT = 2; private static final int CONTENT_SCREEN = 0; private static final int DETAIL_SCREEN = 1; private DelegateViewPager delegateViewPager; private SparseArray<Fragment> activeScreens = new SparseArray<Fragment>(SCREEN_COUNT) ; private DelegateAdapter adapter; public DoubleViewPager(Context context) { this(context, null); } public DoubleViewPager(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DoubleViewPager(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); delegateViewPager = new DelegateViewPager(context); delegateViewPager.setId(R.id.main_page_id); delegateViewPager.setOverScrollMode(ViewPager.OVER_SCROLL_NEVER); final FrameLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER); addView(delegateViewPager, params); } /** * Create a new PagerAdapter and set content fragment as a first object in ViewPager; * @param fragment Fragment you want to use as a main content * @param fm FragmentManager required for ViewPager transactions */ public void initialize(final Fragment fragment, final FragmentManager fm) { adapter = new DelegateAdapter(fm); delegateViewPager.setAdapter(adapter); activeScreens.put(CONTENT_SCREEN, fragment); adapter.notifyDataSetChanged(); } /** * Adds fragment to stack and set it as current selected item. Basically it the same thing as calling * startActivity() with some transitions effects * @param fragment Fragment you want go into */ public void openDetailScreen(Fragment fragment) { activeScreens.put(DETAIL_SCREEN, fragment); adapter.notifyDataSetChanged(); delegateViewPager.setCurrentItem(1, true); } public void hideDetailScreen() { delegateViewPager.setCurrentItem(CONTENT_SCREEN); if (activeScreens.get(DETAIL_SCREEN) != null) { activeScreens.remove(DETAIL_SCREEN); adapter.notifyDataSetChanged(); } } @Override public void onPageScrolled(int i, float v, int i2) { // unused } @Override public void onPageSelected(int i) { if (i == CONTENT_SCREEN) hideDetailScreen(); } @Override public void onPageScrollStateChanged(int i) { // unused } private class DelegateViewPager extends ViewPager { public DelegateViewPager(Context context) { super(context); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { return getCurrentItem() != CONTENT_SCREEN && super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return getCurrentItem() != CONTENT_SCREEN && super.onTouchEvent(event); } } private final class DelegateAdapter extends FragmentPagerAdapter { public DelegateAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { return activeScreens.get(i); } @Override public int getCount() { return activeScreens.size(); } } 

}

这是另一个ViewPager作为SlidingMenu实现它的活动。 (如额外)

 public class DoubleViewPagerActivity extends FragmentActivity { DoubleViewPager doubleViewPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_double_view_pager); doubleViewPager = (DoubleViewPager) findViewById(R.id.doublePager); doubleViewPager.initialize(new MainContentFragment(), getSupportFragmentManager()); } public static final class MainContentFragment extends Fragment { public MainContentFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_doublepager_content_window, parent, false); final ViewPager pager = (ViewPager) view.findViewById(R.id.contentPager); pager.setAdapter(new SimpleMenuAdapter(getChildFragmentManager())); pager.setOffscreenPageLimit(2); pager.setCurrentItem(1); return view; } } public static final class SimpleMenuAdapter extends FragmentPagerAdapter { public SimpleMenuAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { return DoubleViewPagerActivity.PagerFragment.instance(i); } @Override public int getCount() { return 3; } @Override public float getPageWidth(int position) { switch (position) { case 0: case 2: return 0.7f; } return super.getPageWidth(position); } } public static final class PagerFragment extends Fragment { public static PagerFragment instance(int position) { final PagerFragment fr = new PagerFragment(); Bundle args = new Bundle(); args.putInt("position", position); fr.setArguments(args); return fr; } public PagerFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { final FrameLayout fl = new FrameLayout(getActivity()); fl.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); int position = getArguments().getInt("position"); switch (position) { case 0: fl.setBackgroundColor(Color.RED); break; case 1: fl.setBackgroundColor(Color.GREEN); initListView(fl); break; case 2: fl.setBackgroundColor(Color.BLUE); break; } return fl; } private void initListView(FrameLayout fl) { int max = 50; final ArrayList<String> items = new ArrayList<String>(max); for (int i = 1; i <= max; i++) { items.add("Items " + i); } ListView listView = new ListView(getActivity()); fl.addView(listView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER)); listView.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, items)); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ((DoubleViewPagerActivity) getActivity()).doubleViewPager.openDetailScreen(new DetailFragment()); } }); } } public final static class DetailFragment extends Fragment { public DetailFragment() { } @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { FrameLayout l = new FrameLayout(getActivity()); l.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); l.setBackgroundColor(getResources().getColor(android.R.color.holo_purple)); return l; } } 

}