android android二楼 - 像Pinterest或Tumblr一样向后滑动




android下拉刷新框架 swiperefreshlayout使用 (9)

有没有人知道Pinterest或Tumblr如何实现“刷卡”方法。

即在Pinterest上,您可以点击新闻Feed上的帖子。 比DetailActivity启动并显示所选帖子的详细信息。 您可以按后退按钮返回新闻Feed活动,或者您可以向左滑动(详细信息活动)以返回新闻Feed活动。

视频:http: http://youtu.be/eVcSCWetnTA

通常我会使用overridePendingTransition() ,但overridePendingTransition()会获取动画(资源ID如R.anim.foo )。 仅当用户进行滑动手势时,Pinterest和Tumblr才会启动动画。 他们还根据手指移动支持某种“逐帧动画”。 因此,他们跟踪手指移动的距离,并将过渡动画设置为相应的百分比值。

我知道如何使用FragmentTransaction的“真正的java”Animation / AnimatorSet对象来动画片段替换。 使用片段我必须覆盖onCreateAnimator() ,但我不知道如何使用Activities实现类似的东西。 活动是否有onCreateAnimator() (或类似的东西)? 也不知道如何滑动行为,因为它现在没有启动动画,但更多的是逐步改变Window / Activity / Fragment的属性或者其他......

有什么建议?

编辑:我在youtube上找到了一个pinterest应用程序的视频:http: http://youtu.be/eVcSCWetnTA这就是我想要实现的内容。

我猜Pinterest正在使用Fragments和onCreateAnimator()来实现“向后滑动”。 由于我的应用程序已经在一个活动中已经有Fragment和ChildFragments,因此如果我可以为活动实现它,那将更容易。

再一次:我知道如何检测滑动手势,这不是我要求的。 观看youtube视频:http: http://youtu.be/eVcSCWetnTA

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


Answers

我建议做以下事情:

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

我不会复制上述链接中的相关代码,因为我认为这是可接受的答案

其次你可以用这种方法

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

按照此问题的建议执行以下操作

他们谈到用动画完成一项活动

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

希望这对你有所帮助


我写了一个项目。 它允许您轻松开发由Fragments导航的应用程序,就像Pinterest一样。

https://github.com/fengdai/FragmentMaster

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


所以我想我自己找到了解决方案:

首先:Pinterest确实使用了ViewPager和@frozenkoi在他的回答中提到的自定义Page Transformer。 您可以在pinterest应用中看到视图寻呼机的过冲边缘效应。

@Amit Gupta指出了让活动滑动的图书馆。 它与各种导航抽屉的概念相同,并设置了半透明的主题。 他们滑动布局。 但这并不是我想要的,因为它将顶部活动滑动到右边而不是简单地调用finish()。 但是下面的活动不会被动画化。

解决方案是(并且我猜这是Tumblr做的)用动画对象编写你自己的动画并逐步动画它。 这可以通过ActivityOptions完成。 在我看来,这将是解决方案。



我找到了一个基于SwipeBack的GitHub项目,如Pinterest。

它确实是一个很好的开源项目,可以解决您的问题。 它可以根据您的需要进行操作,例如按后退或简单滑动即可转到上一屏幕。 由于这个项目有选择权

1.从左向右滑动

2.从右向左滑动

3.从下滑到顶部

https://github.com/Issacw0ng/SwipeBackLayout

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

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

附上截图: -

希望这会帮助你。


我正在处理我目前正在处理的项目中的这个,并提出了以下代码。 也许它现在与你无关,但它可以帮助这篇文章的新人。 :)

基本上它是你在答案中提到的ViewPager实现,但我认为这是你问题最简单,最快捷的解决方案。 缺点是它只适用于Fragments(可以很容易地更改为Objects),如果你想将ActionBar添加到swipe中,你可能最终会创建一个自定义的。

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

}

}


我能在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以及之前活动的屏幕截图。


我必须承认,通过Android上的文件系统从电子邮件和文件打开附件这一简单任务已成为有史以来最疯狂的经历之一。 处理太多文件很容易,或者太少。 但要做到这一点很困难。 大多数发布在上的解决方案对我来说都不正确。

我的要求是:

  • 让我的应用处理由我的应用共享的附件
  • 让我的应用程序处理由我的应用程序生成的具有特定扩展名的filestorage上的文件

可能要完成此任务的最佳方式是为附件指定自定义MIME类型。 你也可能会选择自定义文件扩展名。 因此,假设我们的应用程序被称为“酷应用程序”,并且我们生成的文件附件最后有“.cool”。

这是最接近我的目标,它的工作......令人满意。

<!-- Register to handle email attachments -->
<!-- WARNING: Do NOT use android:host="*" for these as they will not work properly -->
<intent-filter>
    <!-- needed for properly formatted email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/vnd.coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/coolapp"
        android:pathPattern=".*\\.cool" />
    <!-- needed for mangled email messages -->
    <data
        android:scheme="content"
        android:mimeType="application/octet-stream"
        android:pathPattern=".*\\.cool" />

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

<!-- Register to handle file opening -->
<intent-filter>
    <data android:scheme="file"
          android:mimeType="*/*"
          android:pathPattern=".*\\.cool"
          android:host="*"/>

    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

笔记:

  • pathPattern似乎或多或少被附件忽略(当使用android:scheme="content" )。 如果有人得到pathPattern只响应某些模式,我会很高兴看到如何。
  • 如果我添加了android:host="*"属性,Gmail应用程序拒绝在选择器中列出我的应用程序。
  • 它可能仍然有效,如果这些intent-filter块被合并,但我没有证实这一点。
  • 在下载文件时要处理来自浏览器的请求,可以使用android:scheme="http" 。 请注意,某些浏览器可能会混淆android:mimeType因此请尝试使用android:mimeType="*/*"并在调试器中检查实际传递的内容,然后收紧筛选,以免最终成为处理所有内容的恼人应用。
  • 某些文件探索器也会混淆文件的MIME类型。 上述intent-filter已通过Galaxy S3上的三星“我的文件”应用进行了测试。 FX浏览器仍然拒绝正确打开文件,我也注意到应用程序图标不用于文件。 再次,如果有人得到这个工作,请在下面评论。

我希望你会发现这一点很有用,并且你不必浪费所有可能的组合。 有改进的空间,所以欢迎评论。







android swipe