【问题标题】:Scroll List View one item at time滚动列表一次查看一项
【发布时间】:2016-07-13 06:59:12
【问题描述】:

大家好,我想让我的 Listview 像这样,一次滚动一个项目并且平滑。 这是我迄今为止尝试过的,但没有运气:( 请提前帮助和感谢

自定义 ListView 类

public class SingleScrollListView extends ListView {
private boolean mSingleScroll = false;
private VelocityTracker mVelocity = null;
final private float mEscapeVelocity = 2000.0f;
final private int mMinDistanceMoved = 20;
private float mStartY = 0;

public SingleScrollListView(Context context) {
    super(context);
}

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

public SingleScrollListView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public void setSingleScroll(boolean aSingleScroll) {
    mSingleScroll = aSingleScroll;
}

public int getVerticalScrollOffset() {
    return getFirstVisiblePosition();
}

@Override
public boolean dispatchTouchEvent(MotionEvent aMotionEvent) {
    if (aMotionEvent.getAction() == MotionEvent.ACTION_DOWN) {
        if (mSingleScroll && mVelocity == null)
            mVelocity = VelocityTracker.obtain();
        mStartY = aMotionEvent.getY();
        return super.dispatchTouchEvent(aMotionEvent);
    }

    if (aMotionEvent.getAction() == MotionEvent.ACTION_UP) {
        if (mVelocity != null) {
            if (Math.abs(aMotionEvent.getY() - mStartY) > mMinDistanceMoved) {
                mVelocity.computeCurrentVelocity(1000);
                float velocity = mVelocity.getYVelocity();

                if (aMotionEvent.getY() > mStartY) {
                    // always lock
                    if (velocity > mEscapeVelocity) {
                        smoothScrollToPosition(getFirstVisiblePosition());
                    } else {
                        // lock if over half way there
                        View view = getChildAt(0);
                        if (view != null) {
                            if (view.getBottom() >= getHeight() / 2)
                                smoothScrollToPosition(getFirstVisiblePosition());
                            else
                                smoothScrollToPosition(getFirstVisiblePosition() + 1);
                        }
                    }
                } else {
                    if (velocity < -mEscapeVelocity)

                        smoothScrollToPosition(getFirstVisiblePosition() + 1);
                    else {
                        // lock if over half way there
                        View view = getChildAt(1);
                        if (view != null) {

                            if (view.getTop() <= getHeight() / 2)

                                smoothScrollToPosition(getFirstVisiblePosition() + 1);
                            else
                                smoothScrollToPosition(getFirstVisiblePosition());
                        }
                    }
                }
            }
            mVelocity.recycle();
        }
        mVelocity = null;

        if (mSingleScroll) {
            if (Math.abs(aMotionEvent.getY() - mStartY) > mMinDistanceMoved)
                return super.dispatchTouchEvent(aMotionEvent);
        } else
            return super.dispatchTouchEvent(aMotionEvent);
    }

    if (mSingleScroll) {
        if (mVelocity == null) {
            mVelocity = VelocityTracker.obtain();
            mStartY = aMotionEvent.getY();
        }
        mVelocity.addMovement(aMotionEvent);
    }

    return super.dispatchTouchEvent(aMotionEvent);
}

}

自定义适配器

private class CarListAdapter extends ArrayAdapter<CarList> {
public CarListAdapter() {
    super(MainActivity.this, R.layout.list_view_layout, listArray);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View itemView = convertView;

    if (itemView == null) {
        itemView = getLayoutInflater().inflate(R.layout.list_view_layout, parent, false);
    }

    CarList data = listArray.get(position);
    ImageView Image = (ImageView) itemView.findViewById(R.id.image_holder);
    Image.setImageResource(data.getImageID());

    return itemView;
}

}

列表视图布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/image_holder"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:scaleType="centerCrop"
        android:src="@drawable/car_1" />

【问题讨论】:

  • ImageView 的高度在列表视图布局中应该是“匹配父级”
  • 设置高度后会这样滚动吗?如果您有或可以帮助我编写代码,那么这对我很有帮助
  • 如您所见,图像视图的高度在给定示例中不是“match_parent”,bcz 下一个可用项目有点可见

标签: android listview scroll android-recyclerview


【解决方案1】:

我喜欢您应用的用户界面。对于答案部分,我建议您使用 viewpager 而不是 ListView 。

第一个真正的问题是如何让 viewPager 垂直滚动?

答案是:- 覆盖触摸事件并使用 viewpager 转换器来产生垂直寻呼机的错觉,如 this Answer 中所述。

我这里只是复制sn-p

/**
 * Uses a combination of a PageTransformer and swapping X & Y coordinates
 * of touch events to create the illusion of a vertically scrolling ViewPager. 
 * 
 * Requires API 11+
 * 
 */
public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }

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

    private void init() {
        // The majority of the magic happens here
        setPageTransformer(true, new VerticalPageTransformer());
        // The easiest way to get rid of the overscroll drawing that happens on the left and right
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 1) { // [-1,1]
                view.setAlpha(1);

                // Counteract the default slide transition
                view.setTranslationX(view.getWidth() * -position);

                //set Y position to swipe in from top
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    /**
     * Swaps the X and Y coordinates of your touch event.
     */
    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev); // return touch coordinates to original reference frame for any child views
        return intercepted;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return super.onTouchEvent(swapXY(ev));
    }

}

它看起来像这样

现在第二部分如何使 textView 用于成本随着页面滑动而上升

您可以使用带有 textSwitcher 的垂直视图分页器

costNameSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
    @Override
    public android.view.View makeView() {

        LayoutInflater inflater = LayoutInflater.from(getActivity());
        TextView textView = (TextView) inflater.inflate(R.layout.offer_heading, null);
        return textView;
    }
});

costNameSwitcher.setInAnimation(getActivity(), R.anim.slide_in_up);
costNameSwitcher.setOutAnimation(getActivity(), R.anim.slide_out_up);

然后在页面切换时像这样在 textswitcher 中更改文本

 verticalViewPager
            .addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position,
                                           float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {


                    costNameSwitcher.setText("Some Cost");


                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });

动画

slide_in_up

<?xml version="1.0" encoding="UTF-8"?>
<translate android:toYDelta="0%p" android:fromYDelta="100%p" android:duration="500" xmlns:android="http://schemas.android.com/apk/res/android"/>

slide_out_up

<?xml version="1.0" encoding="UTF-8"?>
<translate android:toYDelta="-100%p" android:fromYDelta="0%p" android:duration="500" xmlns:android="http://schemas.android.com/apk/res/android"/>

带有视图的ViewPager

/**
 * The Class slidingPagerAdapter.
 */
public class slidingPagerAdapter extends PagerAdapter {
    private final List<HotOffer> listOfOffers;
    private Context mContext;
    private LayoutInflater mLayoutInflater;


    /**
     * Instantiates a new home slides pager adapter.
     *
     * @param context       the context
     * @param carousalImage
     */
    public slidingPagerAdapter(Context context, List<HotOffer> carousalImage) {
        mContext = context;
        mLayoutInflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        this.listOfOffers = carousalImage;
    }

    @Override
    public int getCount() {
        return listOfOffers.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == ((FrameLayout) object);
    }

    @Override
    public Object instantiateItem(ViewGroup container, final int position) {
        final View itemView = mLayoutInflater.inflate(R.layout.carousal_page, container,
                false);


        Picasso.with(mContext)
                .load(listOfOffers.get(position).getImageUrl())
                .networkPolicy(NetworkPolicy.OFFLINE)
                .fit()
                .centerCrop()
                .into((ImageView) itemView
                        .findViewById(R.id.image), new Callback() {
                    @Override
                    public void onSuccess() {
                    }


                    @Override
                    public void onError() {
                        // Try again online if cache failed
                        Picasso.with(mContext)
                                .load(listOfOffers.get(position).getImageUrl())
                              .fit()
                                .centerCrop()
                                .into((ImageView) itemView
                                        .findViewById(R.id.image));
                    }
                });


        container.addView(itemView);

        return itemView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((FrameLayout) object);
    }
}

显示一点下一个/上一个视图

  // Disable clip to padding
            viewPager.setClipToPadding(false);
            // set padding manually, the more you set the padding the more you see of prev & next page
            viewPager.setPadding(40, 0, 40, 0);

结果:-

你不需要设置左填充即使用

   viewPager.setPadding(40, 0, 0, 0);

【讨论】:

  • 嗨,感谢您提供宝贵的解决方案...我对使用 ViewPager 有一个疑问,ViewPager 使用 Fragment 并且 Fragment 不会为每个项目动态绘制,我的意思是每个项目我必须制作单独的片段.. . 怎么做
  • 如您在示例图像中看到的...项目未覆盖整个高度,下一个项目在底部可见一点
  • 您可以使用不带片段的 viewpager 见编辑,下一部分见stackoverflow.com/questions/10098040/…
【解决方案2】:

为什么不为此目的使用带有片段的垂直可滚动浏览器。

我在这里复制this的答案供您参考。

您可以使用 ViewPager.PageTransformer 来产生垂直 ViewPager 的错觉。要实现垂直滚动而不是水平拖动,您必须覆盖 ViewPager 的默认触摸事件并在处理它们之前交换 MotionEvents 的坐标,例如:

    /**
     * Uses a combination of a PageTransformer and swapping X & Y coordinates
     * of touch events to create the illusion of a vertically scrolling ViewPager. 
     * 
     * Requires API 11+
     * 
     */

public class VerticalViewPager extends ViewPager {

public VerticalViewPager(Context context) {
    super(context);
    init();
}

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

private void init() {
    // The majority of the magic happens here
    setPageTransformer(true, new VerticalPageTransformer());
    // The easiest way to get rid of the overscroll drawing that happens on the left and right
    setOverScrollMode(OVER_SCROLL_NEVER);
}

private class VerticalPageTransformer implements ViewPager.PageTransformer {

    @Override
    public void transformPage(View view, float position) {

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 1) { // [-1,1]
            view.setAlpha(1);

            // Counteract the default slide transition
            view.setTranslationX(view.getWidth() * -position);

            //set Y position to swipe in from top
            float yPosition = position * view.getHeight();
            view.setTranslationY(yPosition);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

/**
 * Swaps the X and Y coordinates of your touch event.
 */
private MotionEvent swapXY(MotionEvent ev) {
    float width = getWidth();
    float height = getHeight();

    float newX = (ev.getY() / height) * width;
    float newY = (ev.getX() / width) * height;

    ev.setLocation(newX, newY);

    return ev;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent ev){
    boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
    swapXY(ev); // return touch coordinates to original reference frame for any child views
    return intercepted;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    return super.onTouchEvent(swapXY(ev));
}
}

当然,您可以根据需要调整这些设置。

【讨论】:

  • 您可以在运行时调整项目数。您可以更新它,即根据您的要求添加、删除或显示相同的项目。这是可能的,因为我从事类似的项目。附言添加或删除项目后不要忘记致电adapter.notifyDataSetChanged()
  • 感谢您的回复...但请告诉我如何完成任务,正如您在示例中看到的那样,项目没有覆盖整个高度.. 下一个项目也可以在底部看到一点
  • 如果只是一个一个地显示片段,使用图像视图和适当的过渡动画很容易完成。但是您发布的 gif 除了简单的滑动之外,还执行了许多复杂的任务。因此,在此处发布答案可能会解决您的滚动问题,但可能对您稍后执行的操作没有帮助。所以我建议你使用适合你的实现的带有嵌套视图的动画。
猜你喜欢
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 2011-03-18
  • 1970-01-01
  • 2020-02-19
  • 2021-05-26
  • 1970-01-01
相关资源
最近更新 更多