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.