2013-09-30 97 views
38

有人知道Pinterest或Tumblr如何在那裏實施「滑回」方法。像Pinterest或Tumblr一樣向後滑動

即在Pinterest上,您可以點擊新聞提要上的帖子。比DetailActivity啓動並顯示所選帖子的詳細信息。您可以按後退按鈕返回到新聞饋送活動,也可以向左滑動(詳細信息活動)以返回到新聞饋送活動。

視頻:http://youtu.be/eVcSCWetnTA

通常我會用overridePendingTransition(),但overridePendingTransition()需要動畫(資源ID喜歡R.anim.foo)。僅當用戶執行輕掃手勢時,Pinterest和Tumblr纔會啓動動畫。他們還支持根據手指移動的某種「逐幀動畫」。因此,他們追蹤手指移動的距離,並將過渡動畫化爲相應的百分比值。

我知道如何使用具有FragmentTransaction的「真正的java」Animation/AnimatorSet Object來動畫片段替換。有片段,我必須重寫onCreateAnimator(),但我不知道如何使用Activities實現類似的內容。有沒有onCreateAnimator()(或類似的)活動?也不知道如何刷卡的行爲,因爲它現在不開始動畫,但更多的一步一步的屬性改變的窗口/活動/片段或任何...

任何建議嗎?

編輯: 我在youtube上找到了pinterest應用程序的視頻:http://youtu.be/eVcSCWetnTA 那就是我想要實現的。

我想Pinterest正在與Fragments和onCreateAnimator()合作以實現「向後滑動」。 由於我的應用程序已經有一個活動中的Fragment和ChildFragments,如果我可以爲活動實現這個功能,對我來說會更容易。

再次:我知道如何檢測輕掃手勢,這不是我要求的。觀看YouTube視頻:http://youtu.be/eVcSCWetnTA


更新: 我創建了一個小圖書館,裏面有不完全像Pinterest的或Tumblrs執行相同的行爲,但是我的應用程序,這似乎給了我一個很好的解決方案: https://github.com/sockeqwe/SwipeBack?source=c

+0

*比你可以按後退按鈕返回到新聞源活動,或者你可以刷卡(詳情活動)向左回來的新聞供稿活動。* - 你確定這不是一個簡單的'ViewPager'? – Luksprog

+0

沒有它不是viewpager,它是用於從一個活動切換到另一個活動的自定義動畫或FragmentTransaction,如果他們使用Fragment。不過,我想實施類似的活動。對於片段,我可以重寫onCreateAnimator(),但我找不到類似的方法... – sockeqwe

+0

爲什麼不實現某種形式的手勢,然後檢測手勢的起點和終點,並計算它是否是左滑動並且然後用某種動畫停止活動? – Armand

回答

1

所以我想我發現我自己的解決方案:

首先: Pinterest的確實使用了ViewPager使用自定義頁面變壓器像@frozenkoi在答覆提到。您可以在pinterest應用程序中看到查看傳呼機的超額邊緣效應。

@Amit Gupta指出圖書館讓活動滑動。它與各種導航抽屜所具有的相同概念並且也將半透明主題設爲主題。他們滑動佈局。但那不是我正在尋找的,因爲它將頂級活動向右滑動,而不是簡單地調用finish()。但下面的活動將不會動畫英寸

解決方案是(我猜這是Tumblr做的)編寫你自己的動畫與動畫對象和動畫一步一步。 這可以通過ActivityOptions完成。 在我看來,這將是解決方案。

+0

'ActivityOptions'僅在API級別16中添加! –

+2

是的,這是真的。你可以像Pinterst和Path一樣使用ViewPager。但是比你必須實現自己的ActionBar實現等,因爲通常ViewPager不會輕掃默認的操作欄。 – sockeqwe

1

我建議做以下幾點:

首先檢測手勢,用戶在設備做。你可以參考this link

我不打算給相關的代碼從上面的鏈接複製,因爲我相信這是公認的答案

其次,你可以在這個方法

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

執行繼this question

的建議,他們沒有談論與動畫

整理活動3210

希望這可以幫到你

+0

也許我的問題不清楚。我知道如何檢測輕掃手勢,那不是我在尋找什麼。我更新了我的問題,並添加了一個YouTube頻道的鏈接,演示了我在尋找的內容。 – sockeqwe

3

我能在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; 

    } 
} 
+0

感謝您提供的真棒示例代碼。太好了!但我想刷整個活動/窗口。我已更新我的問題,並添加了一個YouTube視頻的鏈接,演示了我在尋找 – sockeqwe

+0

哦......這是一個令人擔憂的PageViewer。 –

+0

這可能是可能的,但我認爲他們正在以某種特殊的方式使用碎片。 – sockeqwe

18

看來,你要找的效果是在Android開發者網站上的樣品ViewPager之一。

檢查出http://developer.android.com/training/animation/screen-slide.html#depth-page,在深度頁變壓器部分。它有一個視頻和源代碼。

使用ViewPager.PageTransformer您可以決定從一個切換到另一個時頁面的行爲。

與鏈接的示例和視頻的唯一區別是左右似乎是倒置的,但應該是我在問題中鏈接的YouTube video上看到的一個很好的起點。這兩個觀點的行動將不得不交換。如這段代碼所示(mPager.setPageTransformer的第一個參數應該是reverseDrawingOrder = false)。注意中間2 if部分被交換,並且position變量被處理稍微不同於開關邊。有彈性的效果留作練習。請在分享時分享!

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); 
      } 
     } 
    } 
7

我發現,是基於SwipeBack像Pinterest的一個GitHub的項目。

這是一個很好的開源項目,應該可以解決您的問題。它可以根據需要進行操作,例如按回或簡單刷卡即可轉到上一個屏幕。作爲這個項目有選項

1向左或向右滑動

2.刷卡從右到左

3.刷卡底部到頂部

https://github.com/Issacw0ng/SwipeBackLayout

,並且您還可以從Google Play安裝此演示應用程序。

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

附截圖: -

enter image description here

希望這會幫助你。

+1

這是一個很好的起點我猜!謝謝! – sockeqwe

+0

這是一個有趣的項目。但目前在4.4.4上有問題。 這裏是[issue](https://github.com/Issacw0ng/SwipeBackLayout/issues/38)我已經打開了它 –

2

我剛剛檢查過層次結構查看器。看起來他們正在使用ViewPager和上一個活動的屏幕截圖。

+0

啊,很高興知道... – sockeqwe

+0

ViewPager(s)不滾動操作欄。我認爲這不是android ViewPager,而是自定義子類,在其中有一些重定製。與此同時,當您在選擇多張照片的帖子後向下滾動(或向上滾動)時,Facebook實施了類似的操作。我敢打賭,這兩個實現幾乎是一樣的。你能弄清楚Facebook使用的是什麼? – doplumi

+0

@domenicop Facebook只是在列表視圖上繪製文章詳細視圖。這一切都在同一活動中完成。 –

8

更新: 修復了此項目的內存使用問題,並將幻燈片樣式更改爲iOS。

enter image description here

我寫了一個演示酷似Pinterest的和tumblr一樣,你只是延長BaseActivity,你會得到一個刷卡回彈效應,工程進展順利!

檢查:https://github.com/chenjishi/SlideActivity

和截圖:enter image description here

+0

看起來像pinterest有不同的實現(可能不是基於捕獲第一個活動的截圖?),因爲從橫向切換到肖像(在第二個活動)它仍然正常工作。 – sandrstar

+2

@sandrstar Pinterest不使用屏幕截圖,它們的所有可滾動頁面都是碎片,因此它們使用ViewPager向後滑動.Tumblr使用截圖,但對OutOfMemory來說非常容易,因爲高清截圖太大而無法處理,所以Pinterest的方法更好。 –

0

我寫了一個項目。它允許您輕鬆開發由Fragments導航的應用程序,就像Pinterest一樣執行操作。

https://github.com/fengdai/FragmentMaster

也許這不是你想要的答案。但我希望這對其他人有用。

+0

這不是問題的答案。這應作爲OP的評論發佈。 – Fr0zenFyr

+0

這是一個問題的解決方案。 –

0

我正在處理這個項目我目前正在處理,並提出了以下代碼。也許它現在與你無關,但它可以幫助在這篇文章中有新的人。 :)

基本上它是ViewPager的實現,正如你在答案中提到的那樣,但我認爲這是對你的問題最簡單和最快的解決方案。缺點是它只適用於碎片(可以很容易地更改爲對象),並且如果要將ActionBar添加到滑動條中,最終可能會創建一個自定義的。

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; 
    } 

} 

}