类似画廊的视图,带有中心图片放大效果。

5
这里我需要一个类似图库的视图,屏幕上只显示三张图片。中间的图片将比两侧的其他图片大。
如果用户滚动视图,下一张图片将在屏幕上滑动,就像在图库中一样。同时,每次只显示三张图片,其中心图片应在显示在屏幕上时自动缩放,而其余两张图片应较小。
这里不能使用Android中已经被弃用的图库。
通过查看此链接上的代码,我得以借助viewpager制作出类似图库的视图。它一次只显示三张图片,符合我的要求。但是我无法获取屏幕上可见的中央图像并对其进行缩放。虽然我能够获取屏幕上单击的图像。
请问有人可以告诉我需要在哪里修改代码,并添加什么内容以获取屏幕上显示的图像中心并对其进行缩放吗?
我知道根据viewpager的定义,在屏幕上没有中心图像,它只是因为代码的修改而一次显示了三张图片。
我还尝试过:
- 具有水平滚动的GridView - 具有水平线性布局的HorizontalScrollView
但是viewpager似乎是更好的解决方案,因为它基于其固有属性,在屏幕上只显示三个项目时停止滚动。
如果有人知道其他方法来实现此目的,请告诉我,我会尝试一下。
附言:对于想要完整代码的任何人,我已经将其作为答案添加了进去,其中还具有缩放功能。只需在接受的答案中增加几个内容即可。 :)

你是指电影带视图吗? - dumbfingers
@ss1271 是的,就像电影带视图一样,并且具有自动缩放功能,以便于屏幕上当前显示的图像中心图像的显示。 - DroidDev
2个回答

14

以下代码将帮助您制作一个带有中心锁定的画廊式视图。它可以响应触摸和滑动操作。一次会显示三张图片在屏幕上,并放大中心图像。

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class CenteringHorizontalScrollView extends HorizontalScrollView implements View.OnTouchListener {

    private Context mContext;
    private static final int SWIPE_PAGE_ON_FACTOR = 10;
    private int mActiveItem;
    private float mPrevScrollX;
    private boolean mStart;
    private int mItemWidth;

    View targetLeft, targetRight;
    ImageView leftImage, rightImage;

    public CenteringHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext=context;
        mItemWidth = 100; // or whatever your item width is.
        setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int x = (int) event.getRawX();

        boolean handled = false;
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if (mStart) {
                    mPrevScrollX = x;
                    mStart = false;
                }
                break;
            case MotionEvent.ACTION_UP:
                mStart = true;
                int minFactor = mItemWidth / SWIPE_PAGE_ON_FACTOR;

                if ((mPrevScrollX - (float) x) > minFactor) {
                    if (mActiveItem < getMaxItemCount() - 1) {
                        mActiveItem = mActiveItem + 1;
                    }
                }else if (((float) x - mPrevScrollX) > minFactor) {
                    if (mActiveItem > 0) {
                        mActiveItem = mActiveItem - 1;
                    }
                }

                scrollToActiveItem();

                handled = true;
                break;
        }

        return handled;
    }

    private int getMaxItemCount() {
        return ((LinearLayout) getChildAt(0)).getChildCount();
    }

    private LinearLayout getLinearLayout() {
        return (LinearLayout) getChildAt(0);
    }

    /**
     * Centers the current view the best it can.
     */
    public void centerCurrentItem() {
        if (getMaxItemCount() == 0)
            return;

        int currentX = getScrollX();
        View targetChild;
        int currentChild = -1;

        do {
            currentChild++;
            targetChild = getLinearLayout().getChildAt(currentChild);
        } while (currentChild < getMaxItemCount() && targetChild.getLeft() < currentX);

        if (mActiveItem != currentChild) {
            mActiveItem = currentChild;
            scrollToActiveItem();
        }
    }

    /**
     * Scrolls the list view to the currently active child.
     */
    private void scrollToActiveItem() {
        int maxItemCount = getMaxItemCount();
        if (maxItemCount == 0)
            return;

        int targetItem = Math.min(maxItemCount - 1, mActiveItem);
        targetItem = Math.max(0, targetItem);

        mActiveItem = targetItem;

        // Scroll so that the target child is centered
        View targetView = getLinearLayout().getChildAt(targetItem);
    
        ImageView centerImage = (ImageView)targetView;
        int height=300;//set size of centered image
        LinearLayout.LayoutParams flparams = new LinearLayout.LayoutParams(height, height);
        centerImage.setLayoutParams(flparams);

        //get the image to left of the centered image
        if((targetItem-1)>=0){
            targetLeft = getLinearLayout().getChildAt(targetItem-1);
            leftImage = (ImageView)targetLeft;
            int width=250;//set the size of left image
            LinearLayout.LayoutParams leftParams = new LinearLayout.LayoutParams(width,width);
            leftParams.setMargins(0, 30, 0, 0);
            leftImage.setLayoutParams(leftParams);
        }

        //get the image to right of the centered image
        if((targetItem+1)<maxItemCount){
            targetRight = getLinearLayout().getChildAt(targetItem+1);
            rightImage = (ImageView)targetRight;
            int width=250;//set the size of right image
            LinearLayout.LayoutParams rightParams = new LinearLayout.LayoutParams(width,width);
            rightParams.setMargins(0, 30, 0, 0);
            rightImage.setLayoutParams(rightParams);
        }
    
        int targetLeft = targetView.getLeft();
        int childWidth = targetView.getRight() - targetLeft;
    
        int width = getWidth() - getPaddingLeft() - getPaddingRight();
        int targetScroll = targetLeft - ((width - childWidth) / 2);
    
        super.smoothScrollTo(targetScroll, 0);
    }

    /**
     * Sets the current item and centers it.
     * @param currentItem The new current item.
     */
    public void setCurrentItemAndCenter(int currentItem) {
        mActiveItem = currentItem;
        scrollToActiveItem();
    }

}

在您的xml中添加水平滚动视图,如下所示:

<com.yourpackagename.CenteringHorizontalScrollView
    android:id="@+id/HSVImage"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/Horizontalalternative">

    <LinearLayout
        android:id="@+id/linearImage"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">
    </LinearLayout>
</com.yourpackagename.CenteringHorizontalScrollView>

在您的活动中定义线性布局。

LinearLayout imageGallery;

然后按以下方式获取:

imageGallery=(LinearLayout)findViewById(R.id.linearImage);

现在您需要将imageView添加到LinearLayout中。在这里,我假设您的图像位于drawable文件夹中,并且您已经创建了一个图像ID数组,该数组包含您想要添加到画廊中的图像。因此,您可以通过以下方法在活动中完成它:

for(int i=0; i<lengthOfImageIdArray; i++){
    ImageView image=new ImageView(YourActivityName.this);
    image.setBackgroundResource(yourArrayName[i]);
    imageGallery.addView(image);
}

您还可以动态设置图像的宽度,以便其适应每个屏幕,只需额外付出一点努力。


是的,它可以正常工作...但我需要像封面流动动画一样的图像...中心图像缩小,左右图像在中心图像下方..所以你能帮我吗?我真的很困惑。 - Denny Sharma
1
请参考此链接:http://stackoverflow.com/questions/18864772/carousel-animation-in-android - Denny Sharma
@DennySharma 很高兴知道你乐于帮助他人,我回答了这个问题。 - DroidDev
1
@shihab_returns:我也做过这个。你需要在for循环中创建一个相对布局,在其中添加一个textView和一个imageView。然后,您需要将此相对布局添加到您的imageGallery中,就像我们在for循环中所做的那样。然后,您可以使用相对布局固有的属性将视图设置为顶部和底部或一个接一个。您需要使用LayoutParams进行设置。请记得更改您的centeringHorizontalScrollView类,因为它将给出class cast异常,以将relative layout转换为imageView。因此,您还需要在该类中获取第一个相对布局。 - DroidDev
1
然后,您需要通过getChildAt()方法获取imageView。只有这样,您才能增加或减小图像的大小。这涉及到一些代码处理。我希望您能理解这个逻辑。我不能在评论中发布整个代码,但即使您需要帮助,请告诉我,我会尽力而为。 - DroidDev
显示剩余14条评论

12

在你的ViewPager中覆盖setPrimaryItem并使中心项更大。

使用HorizontalScrollView和LinearLayout有什么问题?如果要居中,您可以尝试类似于这样的操作(假设您已经...)

/**
 * A centering HSV loosely based on http://iotasol.blogspot.com/2011/08/creating-custom-horizontal-scroll-view.html
 */
public class CenteringHorizontalScrollView extends HorizontalScrollView implements View.OnTouchListener {

    private static final int SWIPE_PAGE_ON_FACTOR = 10;

    private int mActiveItem;

    private float mPrevScrollX;

    private boolean mStart;

    private int mItemWidth;

    public CenteringHorizontalScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mItemWidth = 100; // or whatever your item width is.
        setOnTouchListener(this);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int x = (int) event.getRawX();

        boolean handled = false;
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if (mStart) {
                    mPrevScrollX = x;
                    mStart = false;
                }

                break;
            case MotionEvent.ACTION_UP:
                mStart = true;
                int minFactor = mItemWidth / SWIPE_PAGE_ON_FACTOR;

                if ((mPrevScrollX - (float) x) > minFactor) {
                    if (mActiveItem < getMaxItemCount() - 1) {
                        mActiveItem = mActiveItem + 1;
                    }
                }
                else if (((float) x - mPrevScrollX) > minFactor) {
                    if (mActiveItem > 0) {
                        mActiveItem = mActiveItem - 1;
                    }
                }

                scrollToActiveItem();

                handled = true;
                break;
        }

        return handled;
    }

    private int getMaxItemCount() {
        return ((LinearLayout) getChildAt(0)).getChildCount();
    }

    private LinearLayout getLinearLayout() {
        return (LinearLayout) getChildAt(0);
    }

    /**
     * Centers the current view the best it can.
     */
    public void centerCurrentItem() {
        if (getMaxItemCount() == 0) {
            return;
        }

        int currentX = getScrollX();
        View targetChild;
        int currentChild = -1;

        do {
            currentChild++;
            targetChild = getLinearLayout().getChildAt(currentChild);
        } while (currentChild < getMaxItemCount() && targetChild.getLeft() < currentX);

        if (mActiveItem != currentChild) {
            mActiveItem = currentChild;
            scrollToActiveItem();
        }
    }

    /**
     * Scrolls the list view to the currently active child.
     */
    private void scrollToActiveItem() {
        int maxItemCount = getMaxItemCount();
        if (maxItemCount == 0) {
            return;
        }

        int targetItem = Math.min(maxItemCount - 1, mActiveItem);
        targetItem = Math.max(0, targetItem);

        mActiveItem = targetItem;

        // Scroll so that the target child is centered
        View targetView = getLinearLayout().getChildAt(targetItem);

        int targetLeft = targetView.getLeft();
        int childWidth = targetView.getRight() - targetLeft;

        int width = getWidth() - getPaddingLeft() - getPaddingRight();
        int targetScroll = targetLeft - ((width - childWidth) / 2);

        super.smoothScrollTo(targetScroll, 0);
    }

    /**
     * Sets the current item and centers it.
     * @param currentItem The new current item.
     */
    public void setCurrentItemAndCenter(int currentItem) {
        mActiveItem = currentItem;
        scrollToActiveItem();
    }
}

实际上,我尝试了简单的水平滚动视图。我没有尝试过将水平滚动视图作为扩展类的方法,但现在我正在尝试。虽然它会产生一些异常,但您能否提供可工作的代码,以便我可以轻松尝试它。 - DroidDev
添加了一个更好的示例,应该可以工作,并且还将处理触摸事件以确保始终有一个居中的项目。 - hamidp
抱歉回复晚了,你发布的代码可以正常工作,但是它只适用于水平滚动视图,可以显示一个锁定在中心的项目,但无法增加图像的高度和宽度。虽然我能够获取当前项目并正在尝试增加其大小,但还是很抱歉给您带来不便。我是Android的新手,正在学习很多东西。我已经为你的答案点赞,并且如果我能够缩放中心图像,我会接受它。 - DroidDev
感谢您宝贵的答案,最终我能够增加中心图像的大小,并在其远离中心时再次减小其大小。再次感谢您的帮助。 - DroidDev
@hamidp 当我使用方法setCurrentItemAndCenter(int currentItem)并手动用手指滚动水平视图时,位置总是错误的。看起来水平滚动视图的位置从索引0重新设置了。你们能检查一下吗? - HendraWD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接