【问题标题】:Android ViewPager like instagram photo activityAndroid ViewPager 喜欢 instagram 照片活动
【发布时间】:2017-12-01 19:52:52
【问题描述】:

我需要为照片和视频标签使用相同的片段,并且仍然有三个标签。 我在 viewpager 中有两个片段,在 tablayout 中有 3 个选项卡。我想实现像instagram这样的viewpager改变效果。我做了什么: 我在下面创建了自定义 viewpager:

public class SwipableViewPager extends ViewPager {
    private float downX;
    private float downY;
    private float mStartDragX;
    private float upX;
    private float upY;
    private boolean dragDisabled;

    private SwipeListener mListener;

    public void setSwipeListener(SwipeListener listener) {
        mListener = listener;
    }

    public SwipableViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        float x = ev.getX();
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = ev.getX();
                downY = ev.getY();
                mStartDragX = x;
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                upX = ev.getX();
                upY = ev.getY();

                float deltaX = downX - upX;
                if(deltaX>-getWidth() && deltaX< -getWidth()/4 && getCurrentItem() == getAdapter().getCount() - 1){
                    mListener.setPageAndEnableDrag();
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mStartDragX - 30 > x && getCurrentItem() == getAdapter().getCount() - 1) {
                    mListener.onSwipeOutAtEnd();
                }
                break;
        }
        if(dragDisabled) {
            return false;
        }
        else{
            return super.onInterceptTouchEvent(ev);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(dragDisabled) return false;
        return super.onTouchEvent(ev);
    }

    public void disableDrag(boolean disabled) {
        dragDisabled = disabled;
    }



    public interface SwipeListener {
        void setPageAndEnableDrag();
        void onSwipeOutAtEnd();
    }
}

当当前项目是适配器中的最后一个项目时,它将通知向右滑动(当您在照片选项卡中并且想要通过滑动进入视频选项卡时需要这样做)。 在活动中,我这样设置 viewpager:

private void setupViewPager() {
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        adapter.addFragment(GalleryFragment.newInstance(), getResources().getString(R.string.gallery_toolbar_title));
        TakePhotoFragment fragment = new TakePhotoFragment();
        adapter.addFragment(fragment, getResources().getString(R.string.photo));
        viewPager.setAdapter(adapter);
        viewPager.setSwipeListener(this);
        tabLayout.setupWithViewPager(viewPager);
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {

                switch (tab.getPosition()){
                    case 1:  //selected photo tab
                        viewPager.setCurrentItem(1);
                        toolbar.setTitle(R.string.photo);
                        viewPager.disableDrag(false);    //switch on default swipe
                        break;
                    case 2: // selected video tab
                        toolbar.setTitle(R.string.video);
                        viewPager.disableDrag(true);    // switch off default swipe
                        break;
                    default: // selected gallery tab
                        viewPager.setCurrentItem(tab.getPosition());
                        toolbar.setTitle(R.string.gallery_toolbar_title);
                        viewPager.disableDrag(false);    //switch on default swipe
                        break;
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    @Override
    public void setPageAndEnableDrag() {
        tabLayout.getTabAt(1).select();
        viewPager.disableDrag(false);
    }
    public void setPagerEnabledDrag(boolean enabled) {
        viewPager.disableDrag(!enabled);
    }
    @Override
    public void onSwipeOutAtEnd() {
        viewPager.disableDrag(true);
        tabLayout.getTabAt(2).select();
    }

一切都好,但是当您在画廊标签中并且如果您想进入视频标签时,您无法通过单击视频标签来完成。当您首先单击视频选项卡时,它会激活照片选项卡,然后如果您再单击视频选项卡,它将激活视频选项卡。还可以通过刷丑来改变照片标签和视频标签。 我需要实现点击视频标签时它必须转到视频标签而不是像现在这样的照片标签。

另见视频: https://youtu.be/tbT7mzkmydQ

  1. 为什么我只有两个片段,但有三个选项卡? 因为 Camera 对象只能在一个 Activity 中创建,所以我必须为照片和视频选项卡使用一个片段。
  2. 为什么我必须处理无法拖动的问题? 当用户转到第三个选项卡时,我必须禁用 viewpager 的默认滑动效果(如果我不这样做,从第三个选项卡滑动到第二个 viewpager 时将转到第一个选项卡)
  3. 我不想要无限的浏览器。
  4. 我不想简单地从右侧(第三个)片段转到左侧(第一个)片段。

请看视频: Video of my activity in action

【问题讨论】:

  • 我对您的问题有了一个模糊的认识。如果您仅使用“第一”、“第二”和“第三”来编辑完整问题,将会有所帮助。我仍然不明白:当你从一个相机片段转到另一个相机片段时,你想发生什么?选项卡当然应该改变,但是分页器中应该有滑动动画吗?之间是什么?还是你不想发生任何事情?另外,你为什么要刷卡。你不应该处理适配器吗?你能展示你的实现吗?另外,只有两个片段,你如何首先获得三个选项卡?
  • 当您点击视频标签时,它会转到照片标签。单击第二次后,它将转到视频选项卡。你用过 Instagram 吗?
  • 你能发布一段你想要实现的视频吗?

标签: android android-viewpager


【解决方案1】:

据我了解,您需要为照片和视频标签使用相同的片段,并且仍然有三个标签。

从照片滑动到视频标签 - 在第三个标签上添加一个空白片段,在寻呼机适配器中保持其宽度为零。从照片滑动到视频标签时,照片片段将继续显示。

private void setupViewPager(){
        SectionsPagerAdapter adapter =  new SectionsPagerAdapter(getSupportFragmentManager());

        adapter.addFragment(new GalleryFragment());
        adapter.addFragment(new PhotoFragment());
        adapter.addFragment(new Fragment()); //blank fragment

        mViewPager = (ViewPager) findViewById(R.id.viewpager_container);
        mViewPager.setAdapter(adapter);

        mTabLayout = (TabLayout) findViewById(R.id.tabsBottom);
        mTabLayout.setupWithViewPager(mViewPager);

        mTabLayout.getTabAt(0).setText(getString(R.string.gallery));
        mTabLayout.getTabAt(1).setText(getString(R.string.photo));
        mTabLayout.getTabAt(2).setText(getString(R.string.video));
        ...
    }

设置空白标签的宽度为0

public class SectionsPagerAdapter extends FragmentPagerAdapter {
        ...
        @Override
        public float getPageWidth(int position) {
            if (position == 2) {
                return 0;
            }
            return super.getPageWidth(position);
        }
    }

从视频滑动到照片标签 - 增加视频标签的滑动距离,以便在照片标签处停止滑动。将其他选项卡的投掷距离重置为默认值。您将需要 Java Reflection API 来使投掷距离字段可访问,因为它是 ViewPager.class 中的私有字段

final float density = getResources().getDisplayMetrics().density;
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        Field mFlingDistance;
        try {
            mFlingDistance = ViewPager.class.getDeclaredField("mFlingDistance");
            mFlingDistance.setAccessible(true);
            switch (tab.getPosition()){
                case 2: mFlingDistance.set(mViewPager, (int)(200 * density));
                        break;
                default: mFlingDistance.set(mViewPager, (int)(25 * density));
                         break;
            }
         } catch (NoSuchFieldException e) {
             e.printStackTrace();
         } catch (IllegalAccessException e) {
             e.printStackTrace();
         }
     }

     @Override
     public void onTabUnselected(TabLayout.Tab tab) {}

     @Override
     public void onTabReselected(TabLayout.Tab tab) {}
 });

视频链接:https://imgur.com/a/wA3e0

这是一个快速而肮脏的解决方案。您可能需要对其进行微调。

【讨论】:

  • 是的,你没看错!我正在测试你的解决方案,看起来不错。
  • 只有一件事我无法解决:当您尝试通过滑动将标签从视频更改为照片时,它的变化非常快。我该如何解决这个问题?我试图将 flingDistance 更改为 2000 *密度,但它不起作用....
  • 我已经测试过它是否正确设置了这样的投掷: int flingDist = (int) mFlingDistance.get(viewPager); Log.v("fling", "" + flingDist );更改为视频选项卡时的输出为:fling:6000,当其他选项卡为:fling:75
  • 我给了你赏金,因为你的答案解决了一些问题(不是全部)。这就是为什么我会给你赏金但不接受它。
【解决方案2】:

完全不清楚你想要实现什么。为什么只有两个片段,但三个选项卡?为什么要实现刷卡器(刷卡,或者说分页,默认情况下内置在视图页面中)。为什么必须处理无法使用的阻力?这是,或者更确切地说,这将是 viewpager 的一个功能吗?或者它会成为你片段之一的特征吗? (在后者中,你应该把它留在那个片段中。)

您似乎想要一个无限的浏览器(在最右边的片段上向左滑动 (!))。这个对吗?或者你只是想从右边(第三个)片段到左边(第一个)片段?您可以通过ViewPagerTabLayout 的简单实现来做到这一点:页面(片段)将是可滑动/可分页的(滑动两次以从第三个片段切换到第一个片段)并且选项卡将是可单击的(单击一次以做同样的开关)。

由于您在任何地方都没有定义片段的顺序,因此请不要说“视频”或“画廊”,而是说第一个和第二个(可能还有第三个)片段。

为了清楚起见,我发布了一个带有标准 viewpager-tablayout-toolbar 设置的活动 - 不需要滑动检测。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final ArrayList<Fragment> fragments = new ArrayList<>();
        // make sure to instantiate and add all your fragments
        // your fragments will probably be of different types
        fragments.add(YourFragment.newInstance("Gallery"));
        fragments.add(YourFragment.newInstance("Video"));
        fragments.add(YourFragment.newInstance("Photo"));

        final Toolbar toolbar = findViewById(R.id.toolbar);

        final ViewPager viewPager = findViewById(R.id.viewpager);
        FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public int getCount() {
                return fragments.size();
            }

            @Override
            public Fragment getItem(int position) {
                return fragments.get(position);
            }

            public CharSequence getPageTitle(int position) {
                return ((YourFragment) fragments.get(position)).getTitle();
            }

        };
        viewPager.setAdapter(adapter);

        TabLayout tabLayout = findViewById(R.id.sliding_tabs);
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                // tab.getPosition() returns index for viewPager.setCurrentItem()
                viewPager.setCurrentItem(tab.getPosition());
                toolbar.setTitle(((YourFragment) fragments.get(tab.getPosition())).getTitle());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
            }
        });
        tabLayout.setupWithViewPager(viewPager);
    }

    // make your fragments implement this interface
    interface FragmentTitle {
        CharSequence getTitle();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 2012-09-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多