I have this RecyclerView that functions as a ticker, the auto scrolling works fine at first but after a period of time it becomes strange (back and forth) and the RecyclerView gets stuck at an item without smooth scrolling anymore, can anyone help me.
this is my layout manager:
LinearLayoutManager layoutManager = new LinearLayoutManager(HomeActivity.this, LinearLayoutManager.HORIZONTAL, false) {
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
LinearSmoothScroller smoothScroller = new LinearSmoothScroller(HomeActivity.this) {
private static final float SPEED = 5500f;// Change this value (default=25f)
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return SPEED / displayMetrics.densityDpi;
}
};
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
};
rvTicker.setLayoutManager(layoutManager);
this is my auto scrolling function:
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}
}
};
handler.postDelayed(runnable,speedScroll);
}
SOLVED, I tweaked the autoscroll function:
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
else {
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}else {
count = 0;
}
}
Log.wtf("tickerAdapter.getItemCount()", tickerAdapter.getItemCount()+"");
Log.wtf("count", count+"");
Log.wtf("++count", ++count+"");
Log.wtf("==============","=============");
}
};
handler.postDelayed(runnable,speedScroll);
}
Related
I am using Room data base to fetch the data from the data base. Recyclerview I want to scroll to a particular position in recyclerview.
I have already tried list.setNestedScrollingEnabled(true)
StationListRepository stationListRepositoryOnlyActive = new StationListRepository(getApplicationContext());
stationListRepositoryOnlyActive.getActiveStationList().observe(this, new Observer>() {
#Override
public void onChanged(List OnlyActivestations) {
Log.d("OnlyActivestations", "" + OnlyActivestations.size());
assert OnlyActivestations != null;
if (OnlyActivestations.size() > 0 || FinalList.size() > 0) {
if (FinalList != null && FinalList.size() > 0) {
OnlyActivestations = sortList(OnlyActivestations);
FinalList.addAll(OnlyActivestations);
} else {
OnlyActivestations = sortList(OnlyActivestations);
FinalList = OnlyActivestations;
}
Log.d("FinalListSizeActive",""+FinalList.size());
detailsAdapter = new db_stationListAdapter(context, FinalList);
//recyclerView.setNestedScrollingEnabled(true);
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
staggeredGridLayoutManager.scrollToPosition(10);
recyclerView.setLayoutManager(staggeredGridLayoutManager);
recyclerView.setAdapter(detailsAdapter);
detailsAdapter.notifyDataSetChanged();
runOnUiThread(new Runnable() {
#Override
public void run() {
// stopLoading();
stopAnimation();
}
});
}
}
});
I except the recycler view to auto scroll to the position 10
Try using the code below after you set the data to the adapter
recyclerView.smoothScrollToPosition(10);
or
You can add OnLayoutChangeListener to your RecyclerView.
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener(){
#Override
public void onLayoutChange(View v, int left, int top, int
right, int bottom, int oldLeft, int oldTop, int oldRight,
int oldBottom) {
if (bottom < oldBottom) {
recyclerView.postDelayed(new Runnable() {
#Override
public void run() {
recyclerView.smoothScrollToPosition(10);
}
}, 100);
}
}
});
I am new to Android development. I am trying to create an auto scroll recyclerview slider which also supports user events such as next and previous buttons and manual scrolling.
Something like this:
I have implemented the recyclerview and buttons events handling but I don't know how to implementing auto scroll, it is only scrolling from position 0 to the end and how to stop the auto scroll if the user swiped the slider manually or clicked on the buttons.
MainActivity.java
public class MainActivity extends AppCompatActivity {
RecyclerView mRecyclerView;
LinearLayoutManager layoutManager;
HorizontalSliderAdapter recyclerAdapter;
Button btnPrev;
Button btnNext;
Runnable runnable;
Handler handler;
public static final String LOGTAG = "slider";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.horizontal_slider_recyclerview);
setUpRecyclerView();
autoScroll();
}
public void setUpRecyclerView() {
final List<HorizontalSliderModel> RowItems = HorizontalSliderModel.getData();
layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setHasFixedSize(true);
recyclerAdapter = new HorizontalSliderAdapter(this, RowItems);
mRecyclerView.setAdapter(recyclerAdapter);
btnPrev = (Button) findViewById(R.id.bPrev);
btnNext = (Button) findViewById(R.id.bNext);
btnPrev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mRecyclerView.getLayoutManager().scrollToPosition(layoutManager.findFirstVisibleItemPosition() - 1);
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mRecyclerView.getLayoutManager().scrollToPosition(layoutManager.findLastVisibleItemPosition() + 1);
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
float targetBottomPosition1 = mRecyclerView.getX();
float targetBottomPosition2 = mRecyclerView.getX() + mRecyclerView.getWidth();
Log.i(LOGTAG, "targetBottomPosition1 = " + targetBottomPosition1);
Log.i(LOGTAG, "targetBottomPosition2 = " + targetBottomPosition2);
View v1 = mRecyclerView.findChildViewUnder(targetBottomPosition1, 0);
View v2 = mRecyclerView.findChildViewUnder(targetBottomPosition2, 0);
float x1 = targetBottomPosition1;
if (v1 != null) {
x1 = v1.getX();
}
float x2 = targetBottomPosition2;
if (v2 != null) {
x2 = v2.getX();
}
Log.i(LOGTAG, "x1 = " + x1);
Log.i(LOGTAG, "x2 = " + x2);
float dx1 = Math.abs(mRecyclerView.getX() - x1);
float dx2 = Math.abs(mRecyclerView.getX() + mRecyclerView.getWidth() - x2);
Log.i(LOGTAG, "dx1 = " + dx1);
Log.i(LOGTAG, "dx2 = " + dx2);
float visiblePortionOfItem1 = 0;
float visiblePortionOfItem2 = 0;
if (x1 < 0 && v1 != null) {
visiblePortionOfItem1 = v1.getWidth() - dx1;
}
if (v2 != null) {
visiblePortionOfItem2 = v2.getWidth() - dx2;
}
Log.i(LOGTAG, "visiblePortionOfItem1 = " + visiblePortionOfItem1);
Log.i(LOGTAG, "visiblePortionOfItem2 = " + visiblePortionOfItem2);
int position = 0;
if (visiblePortionOfItem1 >= visiblePortionOfItem2) {
position = mRecyclerView.getChildAdapterPosition(mRecyclerView.findChildViewUnder(targetBottomPosition1, 0));
} else {
position = mRecyclerView.getChildAdapterPosition(mRecyclerView.findChildViewUnder(targetBottomPosition2, 0));
}
mRecyclerView.scrollToPosition(position);
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
break;
case RecyclerView.SCROLL_STATE_SETTLING:
break;
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
}
});
}
public void autoScroll() {
final int speedScroll = 2000;
handler = new Handler();
runnable = new Runnable() {
int count = -1;
#Override
public void run() {
if (count < mRecyclerView.getAdapter().getItemCount()) {
mRecyclerView.smoothScrollToPosition(++count);
handler.postDelayed(this, speedScroll);
}
if (count == mRecyclerView.getAdapter().getItemCount()) {
mRecyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(MainActivity.this));
mRecyclerView.smoothScrollToPosition(--count);
handler.postDelayed(this, speedScroll);
}
}
};
handler.post(runnable);
}
}
About the auto-scroll, I just started a new master/detail template in Android Studio.
Can you try to use this class as your recyclerView's layout manager ?
public class ScrollingLinearLayoutManager extends LinearLayoutManager {
private final int duration;
public ScrollingLinearLayoutManager(Context context, int orientation, boolean reverseLayout, int duration) {
super(context, orientation, reverseLayout);
this.duration = duration;
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
View firstVisibleChild = recyclerView.getChildAt(0);
int itemHeight = firstVisibleChild.getHeight();
int currentPosition = recyclerView.getChildLayoutPosition(firstVisibleChild);
int distanceInPixels = Math.abs((currentPosition - position) * itemHeight);
if (distanceInPixels == 0) {
distanceInPixels = (int) Math.abs(firstVisibleChild.getY());
}
SmoothScroller smoothScroller = new SmoothScroller(recyclerView.getContext(), distanceInPixels, duration);
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class SmoothScroller extends LinearSmoothScroller {
private final float distanceInPixels;
private final float duration;
public SmoothScroller(Context context, int distanceInPixels, int duration) {
super(context);
this.distanceInPixels = distanceInPixels;
this.duration = duration;
}
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return ScrollingLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
#Override
protected int calculateTimeForScrolling(int dx) {
float proportion = (float) dx / distanceInPixels;
return (int) (duration * proportion);
}
}
}
And set it like this
recyclerView.setAdapter(new SimpleItemRecyclerViewAdapter(DummyContent.ITEMS));
recyclerView.setLayoutManager(new ScrollingLinearLayoutManager(this, LinearLayoutManager.VERTICAL, false, 5000));
And trigger it this way
recyclerView.smoothScrollToPosition(recyclerView.getAdapter().getItemCount());
PagerSnapHelper solved my problem.
binding.recyclerViewHomeAnnouncement.apply {
layoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, false)
binding.recyclerViewHomeAnnouncement.layoutManager = layoutManager
setHasFixedSize(true)
itemAnimator = DefaultItemAnimator()
adapter = homeAnnouncementAdapter
}
val snapHelper: SnapHelper = PagerSnapHelper()
snapHelper.attachToRecyclerView(binding.recyclerViewHomeAnnouncement)
This is what I want:
As image above, I want to draw a center line on RecycleView, then get the center item when scrolling (as well as move left or right)
Here is my try to draw a horizontal RecycleView:
HorizontalAdapter adapter = new HorizontalAdapter(data);
LinearLayoutManager layoutManager
= new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recycleView.setLayoutManager(layoutManager);
recycleView.setAdapter(adapter);
Is there any way to know which item is moved to the center of RecycleView? And how can I scroll RecycleView to left or right just one position?
Update: I tried to use a scroll listener to get the middle position, but it doesn't work as an aspect.
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstPos = layoutManager.findFirstVisibleItemPosition();
int lastPos = layoutManager.findLastVisibleItemPosition();
int middle = Math.abs(lastPos - firstPos) / 2 + firstPos;
int selectedPos = -1;
for (int i = 0; i < adapter.getItemCount(); i++) {
if (i == middle) {
adapter.getItem(i).setSelected(true);
selectedPos = i;
} else {
adapter.getItem(i).setSelected(false);
}
}
adapter.notifyDataSetChanged();
}
And get the result:
I only want to change the selected item (make text to white color) when it is on the blue Rect
I made something just like this. I can do exactly what you need.
First of all, this is how is my alogrithm work
This is my recyclerView Adapter
public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;
private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int paddingWidthDate = 0;
private int selectedItem = -1;
public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
this.dateDataList = dateData;
this.paddingWidthDate = paddingWidthDate;
}
#Override
public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_date,
parent, false);
return new DateViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_padding,
parent, false);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.width = paddingWidthDate;
view.setLayoutParams(layoutParams);
return new DateViewHolder(view);
}
}
#Override
public void onBindViewHolder(DateViewHolder holder, int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
if(labelerDate.dateType.equals(BirthDayActivity.DateType.C31))
holder.tvDate.setText(String.valueOf(labelerDate.valueDate));
holder.tvDate.setVisibility(View.VISIBLE);
holder.imgSmall.setVisibility(View.VISIBLE);
if (position == selectedItem) {
holder.tvDate.setTextColor(Color.parseColor("#094673"));
holder.tvDate.setTextSize(35);
holder.imgSmall.setBackgroundResource(R.color.textviewbold);
} else {
holder.tvDate.setTextColor(Color.GRAY);
holder.tvDate.setTextSize(35);
holder.imgSmall.setBackgroundResource(R.color.gray);
}
}
}
public void setSelecteditem(int selecteditem) {
this.selectedItem = selecteditem;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return dateDataList.size();
}
#Override
public int getItemViewType(int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (labelerDate.dateType.equals(BirthDayActivity.DateType.NONE)) {
return VIEW_TYPE_PADDING;
}
return VIEW_TYPE_ITEM;
}
public class DateViewHolder extends RecyclerView.ViewHolder {
public TextView tvDate;
public ImageView imgSmall;
public DateViewHolder(View itemView) {
super(itemView);
tvDate = (TextView) itemView.findViewById(R.id.tvNumberDate);
imgSmall = (ImageView) itemView.findViewById(R.id.small_marked_dob);
}
}}
This is most important alogrithm:
public void getRecyclerviewDate() {
recyclerViewDate = (RecyclerView) findViewById(R.id.recyclerViewDay);
ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
finalWidthDate = recyclerViewDate.getMeasuredWidth();
itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
paddingDate = (finalWidthDate - itemWidthDate) / 2;
firstItemWidthDate = paddingDate ;
allPixelsDate = 0;
final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerViewDate.setLayoutManager(dateLayoutManager);
recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
synchronized (this) {
if(newState == RecyclerView.SCROLL_STATE_IDLE){
calculatePositionAndScrollDate(recyclerView);
}
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
allPixelsDate += dx;
}
});
if (labelerDates == null)
labelerDates = new ArrayList<>();
labelerDates.addAll(genLabelerDate(currentMonth, currentYear));
dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
recyclerViewDate.setAdapter(dateAdapter);
return true;
}
});
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
if (expectedPositionDate == -1) {
expectedPositionDate = 0;
} else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
expectedPositionDate--;
}
scrollListToPositionDate(recyclerView, expectedPositionDate);
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
float missingPxDate = targetScrollPosDate - allPixelsDate;
if (missingPxDate != 0) {
recyclerView.smoothScrollBy((int) missingPxDate, 0);
}
}
private void setDateValue() {
int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
setColorDate = expectedPositionDateColor + 1;
//set color here
dateAdapter.setSelecteditem(setColorDate);
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
allPixelsDate = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE);
allPixelsDateChanged = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED);
}
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putFloat(BUNDLE_LIST_PIXELS_DATE, allPixelsDate);
outState.putFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED, allPixelsDateChanged);
}
And this is my result:
Look at this video link, this is my app demo
Sometimes is needed the entire example code block together, because we may miss something. Here is what I have, feel free to correct anything since I may be doing some little mistake somewhere. And Yes, this answer is an extension of #tranhieu answer. Thanks #tranhieu.
MainActivity.java
package com.test;
import android.app.Activity;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends Activity {
private static final String TAG = MainActivity.class.getSimpleName();
public float firstItemWidthDate;
public float paddingDate;
public float itemWidthDate;
public int allPixelsDate;
public int finalWidthDate;
private DateAdapter dateAdapter;
private ArrayList<LabelerDate> labelerDates = new ArrayList<>();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getRecyclerviewDate();
}
public void getRecyclerviewDate() {
final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
if (recyclerViewDate != null) {
recyclerViewDate.postDelayed(new Runnable() {
#Override
public void run() {
setDateValue();
}
}, 300);
recyclerViewDate.postDelayed(new Runnable() {
#Override
public void run() {
recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
setDateValue();
}
}, 5000);
}
ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
finalWidthDate = recyclerViewDate.getMeasuredWidth();
itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
paddingDate = (finalWidthDate - itemWidthDate) / 2;
firstItemWidthDate = paddingDate;
allPixelsDate = 0;
final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerViewDate.setLayoutManager(dateLayoutManager);
recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
synchronized (this) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
calculatePositionAndScrollDate(recyclerView);
}
}
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
allPixelsDate += dx;
}
});
if (labelerDates == null) {
labelerDates = new ArrayList<>();
}
genLabelerDate();
dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
recyclerViewDate.setAdapter(dateAdapter);
dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
return true;
}
});
}
private void genLabelerDate() {
for (int i = 0; i < 32; i++) {
LabelerDate labelerDate = new LabelerDate();
labelerDate.setNumber(Integer.toString(i));
labelerDates.add(labelerDate);
if (i == 0 || i == 31) {
labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
} else {
labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
}
}
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void calculatePositionAndScrollDate(RecyclerView recyclerView) {
int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
if (expectedPositionDate == -1) {
expectedPositionDate = 0;
} else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) {
expectedPositionDate--;
}
scrollListToPositionDate(recyclerView, expectedPositionDate);
}
/* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/
private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) {
float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate;
float missingPxDate = targetScrollPosDate - allPixelsDate;
if (missingPxDate != 0) {
recyclerView.smoothScrollBy((int) missingPxDate, 0);
}
setDateValue();
}
//
private void setDateValue() {
int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate);
int setColorDate = expectedPositionDateColor + 1;
// set color here
dateAdapter.setSelecteditem(setColorDate);
}
public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;
private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int paddingWidthDate = 0;
private int selectedItem = -1;
public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
this.dateDataList = dateData;
this.paddingWidthDate = paddingWidthDate;
}
#Override
public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_ITEM) {
final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
parent, false);
return new DateViewHolder(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,
parent, false);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.width = paddingWidthDate;
view.setLayoutParams(layoutParams);
return new DateViewHolder(view);
}
}
#Override
public void onBindViewHolder(DateViewHolder holder, int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
holder.tvDate.setText(labelerDate.getNumber());
holder.tvDate.setVisibility(View.VISIBLE);
Log.d(TAG, "default " + position + ", selected " + selectedItem);
if (position == selectedItem) {
Log.d(TAG, "center" + position);
holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
holder.tvDate.setTextSize(35);
} else {
holder.tvDate.setTextColor(Color.WHITE);
holder.tvDate.setTextSize(18);
}
} else {
holder.tvDate.setVisibility(View.INVISIBLE);
}
}
public void setSelecteditem(int selecteditem) {
this.selectedItem = selecteditem;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return dateDataList.size();
}
#Override
public int getItemViewType(int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (labelerDate.getType() == VIEW_TYPE_PADDING) {
return VIEW_TYPE_PADDING;
} else {
return VIEW_TYPE_ITEM;
}
}
public class DateViewHolder extends RecyclerView.ViewHolder {
public TextView tvDate;
public DateViewHolder(View itemView) {
super(itemView);
tvDate = (TextView) itemView.findViewById(R.id.txt_date);
}
}
}
private class LabelerDate {
private int type;
private String number;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
android:id="#+id/rv_tasks_date"
android:layout_width="match_parent"
android:layout_height="48dp" />
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_marginTop="48dp"
android:src="#android:drawable/ic_dialog_info" />
</FrameLayout>
</LinearLayout>
item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="#+id/txt_date"
android:layout_width="#dimen/item_dob_width"
android:layout_height="48dp"
android:text="32"
android:textColor="#android:color/white"
android:background="#android:color/darker_gray"
android:textSize="28sp"
android:gravity="center"/>
</LinearLayout>
dimens.xml
<resources>
<dimen name="item_dob_width">100dp</dimen>
</resources>
Oh boy. I've been searching for this answer for almost a week and then found out the solution. Custom LayoutManagers? No. ItemDecorator? Nope.
Here's the easiest way to do it:
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingStart="150dp"
android:paddingEnd="150dp"
android:clipToPadding="false" />
The critical part is:
android:paddingStart="150dp"
android:paddingEnd="150dp"
android:clipToPadding="false"
And then just assign SnapHelper to your RecylcerView:
val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(recyclerView)
This is it. The easiest and most perfect solution to the problem
I'm used the SnapHelper right here:
// init snaphelper
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView)
// init layout manager
LinearLayoutManager layoutManager = new LinearLayoutManager(mainActivity);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
// init adapter
adatper.setSnapHelper(snapHelper);
adatper.setLayoutManager(layoutManager);
adatper.initAdapter(new Float((DisplayHelper.getDisplayWidth(mainActivity) / 2) - (fooViewWidth / 2)).intValue());
recyclerView.setAdapter(adatper);
As said by TranHieu the solution of inserting 2 item for padding (at start and at end positions) is good.
I don't like the use of ViewTreeObserver because of poor readability of code. With this technique then you must also manage redrawing of the items if they are recycled.
If you are using customview classes you can set its width directly into these classes.
For example this is my padding class
/**
* Created by firegloves on 25/09/15.
*/
#EViewGroup(R.layout.view_padding)
public class PaddingView extends FooView {
Context mCtx;
public PaddingView(Context context) {
super(context);
mCtx = context;
}
public void setWidth(int width) {
setLayoutParams(new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
In my adapter I store the desired padding item width, that is equal to (displayWidth / 2) - (realItemWidth / 2)
This is my adapter, don't look at methods not matching RecyclerView.Adapter, pay attention to the initAdapter method and to the onCreateItemView method
#EBean
public class FooAdapterRecycler extends RecyclerViewAdapterBase<Foo, FooView> {
private final int TYPE_PADDING_VIEW = 0;
private final int TYPE_REAL_VIEW = 1;
#RootContext
Context ctx;
#Bean(Finder.class)
IFinder finder;
SnapHelper snapHelper;
RecyclerView.LayoutManager layoutManager;
private int paddingWidth = 0;
/**
* preleva i dati dal finder
*/
public void initAdapter(int paddingWidth) {
/*******************************
* THIS CODE IS THE IMPORTANT ONE
******************************/
this.paddingWidth = paddingWidth;
// add 1 item for initial space
mItems = new ArrayList<>();
Foo foo = new Foo();
mItems.add(foo);
// get real items from finder
mItems.addAll(finder.findAll());
// add 1 item for final space
mItems = new ArrayList<>();
Foo foo2 = new Foo();
mItems.add(foo2);
}
#Override
public int getItemViewType(int position) {
if (position == 0 || position == getItemCount()-1) {
return TYPE_PADDING_VIEW;
} else {
return TYPE_REAL_VIEW;
}
}
#Override
protected FooView onCreateItemView(ViewGroup parent, int viewType) {
/*******************************
* THIS CODE IS THE IMPORTANT ONE
******************************/
if (viewType == TYPE_PADDING_VIEW) {
PaddingView view = PaddingView_.build(ctx);
view.setWidth(paddingWidth);
return view;
} else {
return FooView_.build(ctx);
}
}
public void setSnapHelper(SnapHelper snapHelper) {
this.snapHelper = snapHelper;
}
public void setLayoutManager(RecyclerView.LayoutManager layoutManager) {
this.layoutManager = layoutManager;
}
}
I'm using AndroidAnnotations library but it's not required
Hope that helps
USING SNAPHELPER - A SMOOTHER SOLUTION
Here it is another solution using SnapHelper. Starting from the answer of #TranHieu here:
https://stackoverflow.com/a/34647005/3944251
and the compressed by #sector11 here:
https://stackoverflow.com/a/38411582/3944251
I wrote the following code which is also based in both answers above, but it's simpler and offers a smoother solution using SnapHelper presented in android support library 24.2.0.
Here you have the MainActivity class. The rest is the same with #sector11's answer.
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.LinearSnapHelper;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
public float firstItemWidthDate;
public float itemWidthDate;
public int allPixelsDate;
public int finalWidthDate;
private DateAdapter dateAdapter;
private ArrayList<LabelerDate> labelerDates;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
labelerDates = new ArrayList<>();
getRecyclerviewDate();
}
public void getRecyclerviewDate() {
final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date);
recyclerViewDate.postDelayed(new Runnable() {
#Override
public void run() {
//recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1);
setDateValue();
}
}, 300);
ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver();
vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this);
finalWidthDate = recyclerViewDate.getMeasuredWidth();
itemWidthDate = getResources().getDimension(R.dimen.item_dob_width);
firstItemWidthDate = (finalWidthDate - itemWidthDate) / 2;
allPixelsDate = 0;
final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext());
dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerViewDate.setLayoutManager(dateLayoutManager);
/* Create a LinearSnapHelper and attach the recyclerView to it. */
final LinearSnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerViewDate);
recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
allPixelsDate += dx;
recyclerView.post(new Runnable() {
public void run() {
setDateValue();
}
});
}
});
genLabelerDate();
dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate);
recyclerViewDate.setAdapter(dateAdapter);
dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1);
return true;
}
});
}
private void genLabelerDate() {
for (int i = 0; i < 32; i++) {
LabelerDate labelerDate = new LabelerDate();
labelerDate.setNumber(Integer.toString(i));
labelerDates.add(labelerDate);
if (i == 0 || i == 31) {
labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING);
} else {
labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM);
}
}
}
//
private void setDateValue() {
int expectedPositionDateColor = Math.round(allPixelsDate / itemWidthDate);
int setColorDate = expectedPositionDateColor + 1;
// set color here
dateAdapter.setSelecteditem(setColorDate);
}
public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;
private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int paddingWidthDate = 0;
private int selectedItem = -1;
public DateAdapter(ArrayList<LabelerDate> dateData, int paddingWidthDate) {
this.dateDataList = dateData;
this.paddingWidthDate = paddingWidthDate;
}
#Override
public DateAdapter.DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
if (viewType == VIEW_TYPE_PADDING) {
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
layoutParams.width = paddingWidthDate;
view.setLayoutParams(layoutParams);
}
return new DateViewHolder(view);
}
#Override
public void onBindViewHolder(DateAdapter.DateViewHolder holder, int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
holder.tvDate.setText(labelerDate.getNumber());
holder.tvDate.setVisibility(View.VISIBLE);
Log.d(TAG, "default " + position + ", selected " + selectedItem);
if (position == selectedItem) {
Log.d(TAG, "center" + position);
holder.tvDate.setTextColor(Color.parseColor("#76FF03"));
holder.tvDate.setTextSize(35);
} else {
holder.tvDate.setTextColor(Color.WHITE);
holder.tvDate.setTextSize(18);
}
} else {
holder.tvDate.setVisibility(View.INVISIBLE);
}
}
public void setSelecteditem(int selecteditem) {
this.selectedItem = selecteditem;
notifyDataSetChanged();
}
#Override
public int getItemCount() {
return dateDataList.size();
}
#Override
public int getItemViewType(int position) {
LabelerDate labelerDate = dateDataList.get(position);
if (labelerDate.getType() == VIEW_TYPE_PADDING) {
return VIEW_TYPE_PADDING;
} else {
return VIEW_TYPE_ITEM;
}
}
public class DateViewHolder extends RecyclerView.ViewHolder {
public TextView tvDate;
public DateViewHolder(View itemView) {
super(itemView);
tvDate = (TextView) itemView.findViewById(R.id.txt_date);
}
}
}
private class LabelerDate {
private int type;
private String number;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
}
You can use a LinearSnapHelper
Attach to your recyclerView like
val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(this)
Then, to get the center view, use
snapHelper.findSnapView(horizontalScrollView.layoutManager)?
As mentioned in the other answer, there is no direct way to do this.
This is probably how you can achieve what you described in the question.
Know the number of items visible on the screen.
Select the middle item programmatically every time the view is scrolled.
Keep a partially transparent image as an overlay on the middle item on the recyclerview. (You'll need to compute the coordinates based on the width of the recycler view or width of the screen and the width of the overlay image you choose to put.
Refresh the selected value in a text view below the recycler view every time there is a scroll.
The image overlays have to be placed in a way they appear connected and as one single control.
For this feature use EcoGallery library:
https://github.com/falnatsheh/EcoGallery
At first, I needed something similar, not this. But I was able to adapt #TranHieu solution to my needs, so I voted up his solution.
I wanted to create full-screen horizontal recyclerview that after user sroll updates scrollPosition to mostVisibleItem.
setup:
private void setUpScrolling() {
mRecyclerVIew.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
mRecyclerVIew.getViewTreeObserver().removeOnPreDrawListener(this);
CustomScrollListener listener = (CustomScrollListener) mScrollListener;
listener.width = mRecyclerVIew.getMeasuredWidth();
listener.dx = 0;
return true;
}
});
}
listener:
private class CustomScrollListener extends OnScrollListener {
private int mLastDx = 0;
int width = 0;
int dx = 0;
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (mLastDx != dx) {
scrollToMostVisibleItem();
} else {
dx = 0;
mLastDx = 0;
}
}
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
this.dx += dx;
}
private void scrollToMostVisibleItem() {
int direction = (dx > 0) ? 1 : -1;
dx = Math.abs(dx);
int shiftCount = Math.round(dx / width);
int pixelShift = dx % width;
if (pixelShift > width / 2) {
shiftCount++;
}
float targetScrollPixels = shiftCount * width;
float finalScrollPixels = (targetScrollPixels - dx) * direction;
if (finalScrollPixels != 0) {
mRecyclerVIew.smoothScrollBy((int) finalScrollPixels, 0);
mLastDx = (int) finalScrollPixels;
dx = 0;
}
}
}
I used another approach in my case.
you can find the deatils here: RecyclerView - How highlight central visible item during scroll1
In my opinion, my solution is more easy than the others.
If someone is looking for a more generic implementation, here is my code based on the answers of this thread:
Add the CenterLinearSnapHelper
public class CenterLinearSnapHelper extends LinearSnapHelper {
//Constants
public static final String TAG = CenterLinearSnapHelper.class.getSimpleName();
//Attributes
private Context context;
private float itemWidth;
private OnPaddingComputationListener listener;
//Constructors
/**
* A linear snap helper which helps centering the items in a recyclerview.
*
* #param itemWidth The (fixed) width of a child view in pixels.
*/
public CenterLinearSnapHelper(float itemWidth) {
this.itemWidth = itemWidth;
}
public void attachToRecyclerView(#Nullable RecyclerView recyclerView,
#NonNull OnPaddingComputationListener listener) throws IllegalStateException {
this.listener = listener;
//Calculates the padding for the first and end item
calculatePadding(recyclerView);
//Create a LinearSnapHelper and attach the recyclerView to it.
attachToRecyclerView(recyclerView);
}
public float getItemWidth() {
return itemWidth;
}
private void calculatePadding(RecyclerView recyclerView) {
if (recyclerView == null)
return;
ViewTreeObserver observer = recyclerView.getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
recyclerView.getViewTreeObserver().removeOnPreDrawListener(this);
int finalWidth = recyclerView.getMeasuredWidth();
float padding = (finalWidth - itemWidth) / 2;
listener.onPadding(padding, finalWidth);
return true;
}
});
}
public interface OnPaddingComputationListener {
void onPadding(float padding, int finalWidth);
}
}
In your Activity/Fragment where you create your RecyclerView:
float itemWidth = getResources().getDimension(R.dimen.favorite_room_width);
CenterLinearSnapHelper snapHelper = new CenterLinearSnapHelper(itemWidth);
snapHelper.attachToRecyclerView(binding.listFavorites, (padding, finalWidth) -> {
//Set the adapter
roomAdapter = new RoomAdapter(requireContext(), rooms);
roomAdapter.addPaddingItems((int) padding);
roomAdapter.setOnToggleClickListener(FavoritesFragment.this);
binding.listFavorites.setAdapter(roomAdapter);
});
In your adapter:
public void addPaddingItems(int padding) {
if (padding < 0)
throw new IllegalStateException("Padding cannot be smaller than 0");
this.padding = padding;
//Add 2 new items as the first and last
//NOTE: If you update your existing dataset (e.g add new items), you should redo the calculation!
rooms.add(0, new Room("First"));
rooms.add(rooms.size(), new Room("Last"));
}
#Override
public int getItemViewType(int position) {
if (padding >= 0 && (position == 0 || position == rooms.size() - 1)) {
return VIEW_TYPE_PADDING;
}
return VIEW_TYPE_ITEM;
}
#NonNull
#Override
public RoomViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
ViewFavoriteRoomBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_favorite_room, parent, false);
if (viewType == VIEW_TYPE_PADDING) {
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) binding.getRoot().getLayoutParams();
layoutParams.width = padding;
binding.getRoot().setLayoutParams(layoutParams);
}
RoomViewHolder viewHolder = new RoomViewHolder(context, binding, onToggleClickListener);
viewHolder.getRecyclerView().setRecycledViewPool(viewPool);
return viewHolder;
}
I am making horizontal scrollview gallery, and I want to autoscroll it. Now it's scrolling from left to right but when I reach end of list I just simply jump to first one, but it looks really bad, so I want to go scroll around from beginning avoiding just skipping to first one, or if it is not possible just start scrolling to the other side when I reach last view on right (maybe better option). Could someone help me how to do this?
private LinearLayout horizontalOuterLayout;
private HorizontalScrollView horizontalScrollview;
private int scrollMax;
private int scrollPos = 0;
private TimerTask clickSchedule;
private TimerTask scrollerSchedule;
private TimerTask faceAnimationSchedule;
private Timer scrollTimer = null;
private Timer faceTimer = null;
private String[] imageNameArray ={ "sponsors_czarnykot", "sponsors_estradarzeszow","sponsors_klubp","sponsors_kula","sponsors_czarnykot", "sponsors_estradarzeszow","sponsors_klubp","sponsors_kula" };
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.horizontal_layout);
horizontalScrollview = (HorizontalScrollView) findViewById(R.id.horiztonal_scrollview_id);
horizontalOuterLayout = (LinearLayout) findViewById(R.id.horiztonal_outer_layout_id);
horizontalScrollview.setHorizontalScrollBarEnabled(false);
addImagesToView();
ViewTreeObserver vto = horizontalOuterLayout.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
horizontalOuterLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
getScrollMaxAmount();
startAutoScrolling();
}
});
}
public void getScrollMaxAmount()
{
int actualWidth = (horizontalOuterLayout.getMeasuredWidth() - 512);
scrollMax = actualWidth;
}
public void startAutoScrolling()
{
if (scrollTimer == null)
{
scrollTimer = new Timer();
final Runnable Timer_Tick = new Runnable()
{
public void run()
{
moveScrollViewRight();
}
};
if (scrollerSchedule != null)
{
scrollerSchedule.cancel();
scrollerSchedule = null;
}
scrollerSchedule = new TimerTask()
{
#Override
public void run()
{
runOnUiThread(Timer_Tick);
}
};
scrollTimer.schedule(scrollerSchedule, 30, 30);
}
}
public void moveScrollViewRight()
{
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
if (scrollPos >= scrollMax)
{
scrollPos = 0;
}
horizontalScrollview.scrollTo(scrollPos, 0);
}
/** Adds the images to view. */
public void addImagesToView()
{
for (int i = 0; i < imageNameArray.length; i++)
{
final ImageView imageView = new ImageView(this);
int imageResourceId = getResources().getIdentifier(imageNameArray[i], "drawable", getPackageName());
Drawable image = this.getResources().getDrawable(imageResourceId);
imageView.setBackgroundDrawable(image);
imageView.setTag(i);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(180, 123);
params.setMargins(0, 25, 0, 25);
imageView.setLayoutParams(params);
horizontalOuterLayout.addView(imageView);
}
}
public void stopAutoScrolling()
{
if (scrollTimer != null)
{
scrollTimer.cancel();
scrollTimer = null;
}
}
public void onBackPressed()
{
super.onBackPressed();
finish();
}
public void onPause()
{
super.onPause();
finish();
}
public void onDestroy()
{
clearTimerTaks(clickSchedule);
clearTimerTaks(scrollerSchedule);
clearTimerTaks(faceAnimationSchedule);
clearTimers(scrollTimer);
clearTimers(faceTimer);
clickSchedule = null;
scrollerSchedule = null;
faceAnimationSchedule = null;
scrollTimer = null;
faceTimer = null;
super.onDestroy();
}
private void clearTimers(Timer timer)
{
if (timer != null)
{
timer.cancel();
timer = null;
}
}
private void clearTimerTaks(TimerTask timerTask)
{
if (timerTask != null)
{
timerTask.cancel();
timerTask = null;
}
}
scrolling back the other way would be easiest.
add in a instance variable that is set to 1.0 (called say scrollDist)
then change this line
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
to
scrollPos = (int) (horizontalScrollview.getScrollX() + scrollDist);
and this line
scrollPos = 0;
to
scrollDist *= -1.0;
this way it will reverse each time it hits the end of the scrollview.
For endless scrolling use the following snnipet
public void getScrollMaxAmount() {
int actualWidth = (horizontalOuterLayout.getMeasuredWidth() - getWindowManager().getDefaultDisplay().getWidth());
scrollMax = actualWidth;
}
public void moveScrollView() {
// ********************* Scrollable Speed ***********************
scrollPos = (int) (horizontalScrollview.getScrollX() + 1.0);
if (scrollPos >= scrollMax) {
Log.v("childCount", ""+scrollMax);
addImagesToView();
getScrollMaxAmount();
}
horizontalScrollview.scrollTo(scrollPos, 0);
}
Can a View Pager be made to auto slide or autopage. I have my viewpager set up to use the adapter like the below and it works fine:-
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gridslide);
ImagePagerAdapter mAdapter = new ImagePagerAdapter(
getSupportFragmentManager(),4);
ViewPager mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
}
And the adapter is like below:-
public static class ImagePagerAdapter extends FragmentStatePagerAdapter {
private final int mSize;
public ImagePagerAdapter(FragmentManager fm, int size) {
super(fm);
mSize = size;
}
#Override
public int getCount() {
return mSize;
}
#Override
public Fragment getItem(int position) {
Log.v(TAG,"position="+position);
return TheFragment.newInstance(position);
}}
However I would want to know how to make these fragments autoslide in a viewpager.
Setting smoothScroll = true in setCurrentItem(int item, boolean smoothScroll) does not always have the smooth scroll effect. Suppose if you have less than 5 pages in you viewpager, you will hardly notice the smooth scroll.
In this scenario, the hard way to do it is to put it in a for loop
//This will scroll page-by-page so that you can view scroll happening
for (int i = 0; i < mAdapter.getCount()-1; i++)
mPager.setCurrentItem(i, true);
If some one needs more slower scroll, they can use postDelayed() like this...
static int i=0;
private final Handler handler = new Handler();
somefunction()
{
handle.post(ViewPagerVisibleScroll);
}
Runnable ViewPagerVisibleScroll= new Runnable() {
#Override
public void run() {
if(i <= mAdapter.getCount()-1)
{
mPager.setCurrentItem(i, true);
handle.postDelayed(TopChartAnimation, 100);
i++;
}
}
};
Sleep is always NOT recommended : If some one needs more slower scroll, they may use a sleep in this for loop...
#Override
public void onClick(View v) {
Runnable runnable = new Runnable() {
#Override
public void run() {
for (int i = 0; i < mAdapter.getCount()-1; i++) {
final int value = i;
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
mPager.setCurrentItem(value, true);
}
});
}
}
};
new Thread(runnable).start();
}
Probably, You should take a look at the following APIs ViewPager.beginFakeDrag(), ViewPager. fakeDragBy(float offset) and ViewPager.endFakeDrag() if You want drag simulation. Also, setCurrentItem() APIs provide ability to set current page and do it smoothly.
Simplest way I could suggest to make slide automatically is to setup Handler with simple Runnable which would call pager methods for setting item in the activity and just do postDelayed() for it. And don't forget to call removeCallbacks() for it when user interaction or e.g. activity pause.
First Create Slider class extend with TimerTask
public class SliderTimer extends TimerTask {
private ViewPager viewPager;
private int size;
private Activity activity;
public SliderTimer(ViewPager viewPager, int size, Activity activity) {
this.viewPager = viewPager;
this.size = size;
this.activity = activity;
}
#Override
public void run() {
activity.runOnUiThread(() -> {
if (viewPager.getCurrentItem() < size - 1) {
viewPager.setCurrentItem(viewPager.getCurrentItem() + 1, true);
} else {
viewPager.setCurrentItem(0, true);
}
});
}
}
Next Create SpeedSlowScroller for slow scrolling
public class SpeedSlowScroller extends Scroller {
private int mDuration = 2500;
public SpeedSlowScroller(Context context) {
super(context);
}
public SpeedSlowScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public SpeedSlowScroller(Context context, Interpolator interpolator, boolean flywheel) {
super(context, interpolator, flywheel);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
#Override
public void startScroll(int startX, int startY, int dx, int dy) {
// Ignore received duration, use fixed one instead
super.startScroll(startX, startY, dx, dy, mDuration);
}
}
Finally add SpeedSlowScroller into ViewPager, and SliderTimer for auto scroll
try {
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
SpeedSlowScroller scroller = new SpeedSlowScroller(_context);
mScroller.set(your_viewpager, scroller);
Timer timer = new Timer();
timer.scheduleAtFixedRate(new SliderTimer(your_viewpager, models.size(), activity), 4000, 6000);
} catch (Exception ignored) {
}
short answer 2020
After you set your viewPager adapter
private Runnable runnable = null;
public void function DisplaySlider(){
sliderItemAdapter = new SliderItemAdapter(getActivity(), mSliderList);//push the data to the adapter
mViewPager.setAdapter(sliderItemAdapter); //set the adapter to the view pager
startAutoSlider(sliderItem.getCount());
}
private void startAutoSlider(final int count) {
runnable = new Runnable() {
#Override
public void run() {
int pos = mViewPager.getCurrentItem();
pos = pos + 1;
if (pos >= count) pos = 0;
mViewPager.setCurrentItem(pos);
handler.postDelayed(runnable, 3000);
}
};
handler.postDelayed(runnable, 3000);
}
And finally don`t forget to free the memory from the callbacks
#Override
public void onDestroy() {
if (runnable != null) handler.removeCallbacks(runnable);
super.onDestroy();
}