Android - 类似轮播的小部件,显示左右元素的一部分

Posted

技术标签:

【中文标题】Android - 类似轮播的小部件,显示左右元素的一部分【英文标题】:Android - Carousel like widget which displays a portion of the left and right elements 【发布时间】:2012-04-17 14:14:33 【问题描述】:

所以我搜索了高低,但找不到我的问题的答案。我基本上需要的是 android 的 ViewFlipper 或 ViewPager 提供的行为,但我想显示左右视图的一部分,以指示用户有要滚动的元素,而不是让选定的视图占据整个屏幕。

我还想为左侧视图和侧视图添加一些效果,例如调暗和缩放,然后再缩小一点。是否可以使用股票 ViewFlipper 或 ViewPager 来实现,或者我必须推出自己的视图组,比如封面流 (http://www.inter-fuser.com/2010/01/android-coverflow-widget.html)?

(P.S. 我不想使用 Gallery 小部件,那个组件很烂)。

这是我们在选择视图后需要显示的内容(仍然显示左右视图):

向左或向右晃动会将主视图移出,使其变暗并稍微减小一点,而对下一个或上一个视图执行相反的操作。

【问题讨论】:

Are you describing this? 关闭,除了选中的视图不应该占据整个屏幕。请参阅上面的编辑,其中包含解释布局的图像。 【参考方案1】:

我想向任何可能想要相同功能的人提供更新。到目前为止,在实现此功能方面已经取得了很大进展,现在视图正在完全按照我们的需要工作。

ViewPager 有一个名为 setPageMargin() 的方法。此方法可以接收一个负值,这将使片段/视图相互重叠。为了达到所需的布局,我们首先按屏幕百分比动态计算左右边距。这也可以静态完成,但由于我们将针​​对一系列不同的屏幕尺寸,这似乎是最好的方法。

稍后我们将 ViewPager 的页边距设置为侧边距大小的 2 倍。这使视图重新组合在一起。但是,此时 ViewPager 将显示多个视图。

您剩下要做的就是对左右视图应用变换(缩放)(Android 3.0+),或者在它们周围添加更多边距以将它们缩小到正确的大小(3.0 之前)。

OnPageChangeListener.onPageScrolled() 可用于跟踪 ViewPager 的滚动。一个光滑的 可以实现转型。代码如下所示:

private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() 

    @Override
    public void onPageSelected(int position) 
    

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 

        // positionOffset varies from 0 to 1 and indicates how far the view is
        // from the center of the ViewPager. When a view is selected (centered), this
        // value is 0.

        // Fades the text in an out while the ViewPager scrolls from one view to another.
        // On our final design the text views are fixed to the center of the screen and
        // do not scroll along with the views.
        if (positionOffset < 0.5) 
            setTextViewAlpha(1 - positionOffset * 2);
         else 
            setTextViewAlpha((positionOffset - 0.5f) * 2);
        

        // It's surprisingly complicated to get the current object being displayed by
        // a ViewPager (there's no getCurrentObject method). ScaleableFragment is just
        // a custom class to allow an adapter to cache it internally and also correctly
        // manage a fragment's lifecycle and restore from a saved state.
        ScaleableFragment sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager
                .getAdapter()).getItem(position);

        // Calculates by how much the current view will be scaled down. The RATIO_SCALE
        // is 0.3 in our case, which makes the side views 70% of the size of the
        // center view. When centered, the scale will be 1. When
        // fully scrolled, the scale will be 0.7.
        float scale = 1 - (positionOffset * RATIO_SCALE);

        // Just a shortcut to findViewById(R.id.image).setScale(scale);
        sampleFragment.scaleImage(scale);


        // Now, if not in the last element, scale the next one up (in opposite direction).
        if (position + 1 < pager.getAdapter().getCount()) 
            sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter())
                    .getItem(position + 1);
            scale = positionOffset * RATIO_SCALE + (1 - RATIO_SCALE);
            sampleFragment.scaleImage(scale);
        
    

    // Once scrolling is done. Make sure the views are in the right scale (1 for center,
    // 0.7 for sides). Required as the onPageScrolled() method does not guarantee it
    // will interpolate to 1.0 precisely.
    @Override
    public void onPageScrollStateChanged(int state) 
        if (state == ViewPager.SCROLL_STATE_IDLE) 
            setTextViewAlpha(1);
            ScaleableFragment sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager
                    .getAdapter()).getItem(pager.getCurrentItem());
            sampleFragment.scaleImage(1);
            sampleFragment.enableClicks();

            if (pager.getCurrentItem() > 0) 
                sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter())
                        .getItem(pager.getCurrentItem() - 1);
                sampleFragment.scaleImage(1 - RATIO_SCALE);
                sampleFragment.disableClicks();
            

            if (pager.getCurrentItem() + 1 < pager.getAdapter().getCount()) 
                sampleFragment = (ScaleableFragment) ((ShowHeroShotImageFragmentPagerAdapter) pager.getAdapter())
                        .getItem(pager.getCurrentItem() + 1);
                sampleFragment.scaleImage(1 - RATIO_SCALE);
                sampleFragment.disableClicks();
            
        
    
;

就是这样。我没有发布完整的解决方案,但我希望这足以让其他人开始。

附:在 3.0+ 上启用硬件加速。没有它,三星 Galaxy Tab 10.1 上的滚动看起来很不稳定。

【讨论】:

我正在使用 setPageMargin 方法,但在横向上没有结果,由于某种原因我现在无法理解,只能在纵向模式下工作,其余的相当简单,但如果我无法得到它在风景中工作然后我的方法(与您对非活动视图应用填充/边距相同)然后这是没用的。除了 setPageMargin 方法之外,我还需要考虑其他一些事情才能正常工作? @Jorge Aguilar 如果不查看源代码,我真的不能说。我们的应用处于横向模式,运行良好。 您好,能否请您发布 sampleFragment.scaleImage(scale); 的代码?使用此代码后,ViewPager 的左/右预览不可见... @user3586231 对不起。我无法再访问此代码。【参考方案2】:

我用它玩了一些,我的解决方案很简单。我把它贴在这里以防有人感兴趣。

首先,每个片段的布局应该允许两边有一些间隙。我发现这样做的最简单方法是使用权重:

<LinearLayout
    android:layout_
    android:layout_
    android:layout_weight="0.1" />

<LinearLayout
    android:layout_
    android:layout_
    android:layout_weight="0.8"
    android:orientation="vertical" >

    <!-- fragment contents go here -->

</LinearLayout>

<LinearLayout
    android:layout_
    android:layout_
    android:layout_weight="0.1" />

这将在两边留下 10% 的不错余量。一定不要在这些上设置背景,因为它会覆盖相邻的片段。 现在对于寻呼机本身:您需要使用负边距,正如 AngraX 解释的那样,但也要确保预加载后续片段,因为它们在定期出现之前是可见的。我得到了很好的结果:

    mPager = (ViewPager) findViewById(R.id.pager);
    mPager.setAdapter(mAdapter);
    mPager.setPageMargin(getResources().getDisplayMetrics().widthPixels / -7);
    mPager.setOffscreenPageLimit(2);

-7 值使下一个片段的边缘可见,请使用您的特定构图。我还建议对每个片段进行构图。

【讨论】:

【参考方案3】:

嗯,这是一个可能的答案,可能与您正在寻找的内容接近,但并不完全是您正在寻找的内容:有一个名为 ViewFlow 的项目,我认为它可以通知用户存在通过屏幕上的指示器获得更多视图。它还提供了在当前视图的左侧和右侧缓冲视图的能力,因此您可以通过基本上缩小它所查看的可用屏幕尺寸来查看代码以呈现它们的一小部分。

编辑:愚蠢的我;在回答之前,我应该阅读最后一个问题。 :) 不幸的是,我认为您无法使用 ViewFlipper 或 Viewpager 来做到这一点。

【讨论】:

无论如何,谢谢。我想避免开发自己的小部件。也许 ViewFlipper 或 ViewPager 的源代码是一个好的开始。【参考方案4】:

只需使用 ViewPager 并使用片段的宽度和边距。我已经这样做了,而且效果很好。

【讨论】:

以上是关于Android - 类似轮播的小部件,显示左右元素的一部分的主要内容,如果未能解决你的问题,请参考以下文章

如何在 spotify 应用程序 API 中创建类似“轮播”的小部件?

图片轮播的小案例

如何jQuery实现图片轮播的同时左右按钮可以实现切换?

Android 轮播图下面左右滑动的小圆点样式布局

Android之仿京东淘宝的自动无限轮播控件

jQuery实现简单的轮播图