简体   繁体   中英

Scroll List View one item at time

Hello guys i would like to make my Listview like this, One item scroll at a time and smooth . here what i've tried so far but no luck :( Please help and thanks in advance

在此处输入图片说明

Custom ListView Class

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

}

Custom Adapter

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

}

List View Layout

<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" />

I liked the UI of your app. For the Answer part I suggest you to use viewpager instead of ListView .

Which come to first real question how to make viewPager scroll vertical ?

Answer is :- override touch events and use use viewpager transformer to give illusion of vertical pager as described in this Answer .

I am just copying snippet here

/**
 * 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));
    }

}

and it look like this

在此处输入图片说明

Now for second part of how to make textView used for cost is go up along with page swipe

You can use vertical view pager with 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);

And on page switch change text in textswitcher like this

 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) {

                }
            });

Animations

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 with views

/**
 * 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);
    }
}

Showing little bit of next/previous view

  // 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);

Result :-

在此处输入图片说明

You dont need to set left padding ie use

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

Why dont you use vertical scrollable viewpager with fragments for this purpose.

I am copying this answer here for your reference.

You can use a ViewPager.PageTransformer to give the illusion of a vertical ViewPager. To achieve scrolling with a vertical instead of a horizontal drag you will have to override ViewPager's default touch events and swap the coordinates of MotionEvents prior to handling them, eg:

    /**
     * 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));
}
}

Of course you can tweak these settings as you see fit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM