I want to make a gridView (or ListView) scrolling automatically (without user interaction) repeatly.
I want it on the background, the user has not the possibility to scroll the gridView, he has only one button in foreground to start an activity. It is just a "presentation" activity
How can I make it possible? I have no idea what to use to do it, if there is somes simple android api to make it.
Should I use animation thread or can it be done only with smoothToScroll?
Use duration
mListView.smoothScrollToPositionFromTop(position, duration);
You have the smoothScrollToPosition method that will scroll to a position on the listview/gridview
http://developer.android.com/reference/android/widget/AbsListView.html#smoothScrollToPosition(int)
As for the possibility to scroll on the gridview/listview just implement a touchListener and return true
For example if you want to to this slowly you can't just create a for. It will scroll too fast. You can use handlers for that. Create a recursive function scrollTo.
public void scrollTo(final ListView myView, final int position) {
final Handler myHandler = new Handler();
myHandler.postDelayed(new Runnable() {
#Override
public void run() {
myView.smoothScrollToPosition(position);
if(position<myView.getAdapter().getCount())
scrollTo(myView, position + 1);
}
}, 2000);
}
And next call it once like scrollTo(myListview,0);. The function will do the rest. Change 2000 for the number of seconds you want to wait *1000.
Related
I basically have to smooth scroll a listview and update a row at the same time.
I do it with a simple approach for now:
mListViewWeeks.post(new Runnable() {
#Override
public void run() {
// update the row concerned
updateItemAtPosition(rowIndex);
int duration = 200;
mListView.smoothScrollToPositionFromTop(rowIndex, 0, duration);
}
});
with the updateItemAtPosition() function:
private void updateItemAtPosition(int position) {
int visiblePosition = mListView.getFirstVisiblePosition();
View view = mListView.getChildAt(position - visiblePosition);
mListView.getAdapter().getView(position, view, mListView);
}
It's working well at a reasonable scroll speed, but when going faster (calling the first block above at a high rate) it can get a bit laggy. Is there anything that I can do to improve updating a row while scrolling smoothly?
You should'nt acces the iew dirrectly like this. Instead you should update your model object displayed by the list and call notifyDataSetChanged() in your adapter.
Well, I'm really late in the game. It looks like one of the reason why RecyclerView was introduced. I'm gonna try to use this component from now on.
A combination of layoutManager.scrollToPosition(position);
and adapter.notifyItemChanged(position); does the job. Everything runs smoothly!!
I have a ListView Object and use:
Timer timer=new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#SuppressLint("NewApi")
#Override
public void run() {
lv1.scrollBy(0, counter_automatic);
counter_automatic++;
}
});
}
}, 0, 100);
code work correctly and don't get any Error! But I want Scrolling to go till end of listView!
My listView has 286 item! but it goes only for 3 items and after 3 items scrolling continue but items don't appear!
What's the problem?
The scrollBy() method is a member of the View class, and isn't going to work as you're expecting for a ListView because of how it handles its child Views. Depending on what exactly the desired behavior is, you probably want to use smoothScrollToPosition(int position) or smoothScrollBy(int distance, int duration).
The scrollBy method takes pixels as parameters. I suppose you mix up of number of items with amount of pixels.
If you want to smooth scroll to a certain item use smoothScrollToPosition instead. See http://developer.android.com/reference/android/widget/AbsListView.html#smoothScrollToPosition(int)
scrollBy() scrolls by an amount of pixel, and not from item to item. The documentation of scrollBy() says:
public void scrollBy (int x, int y)
Move the scrolled position of your view. This will cause a call to onScrollChanged(int, int, int,
int) and the view will be invalidated.
Parameters
x - the amount of pixels to scroll by horizontally
y - the amount of pixels to scroll by vertically
So what you want to do is something like this:
listView.scrollTo(0, listView.getHeight());
Using scrollTo() instead of scrollBy() should be more reliable for your use-case.
But I guess the method you are actually looking for is smoothScrollToPosition()! Try something like this:
listView.smoothScrollToPosition(adapter.getCount() - 1);
Instead of using scrollBy, try using setSelectionFromTop(int position, int pixelsFromTop). In your case, use counter_automatic as position and let the pixelsFromTop variable not change.
I have been working on a ListViewidea where it keeps scrolling automatically with no user interaction and that is absolutely doable using the android APIs for instance smoothScrollToPositionFromTop.
I have implemented ListView BaseAdapter where it load items forever (almost) to get a non stopping self repeated ListView.
What I want to achieve here is to keep myListViewscrolling forever with certain speed (slow) to make items clear and readable while scrolling down, I not sure yet if ListView is my best choice here.
below is a snippet of what I am trying to do. the result is good somehow but it's not smooth enough, I can feel the ListView flickers.
I need to improve smoothness, efficiency and control the speed
new Thread(new Runnable() {
#Override
public void run() {
int listViewSize = mListView.getAdapter().getCount();
for (int index = 0; index < listViewSize ; index++) {
mListView.smoothScrollToPositionFromTop(mListViewA.getLastVisiblePosition() + 100, 0, 6000);
try {
// it helps scrolling to stay smooth as possible (by experiment)
Thread.sleep(60);
} catch (InterruptedException e) {
}
}
}
}).start();
I suggest, thath your adapter implemented in effective way.
so this code is just scrolls listview
you need to try another values of variables
final long totalScrollTime = Long.MAX_VALUE; //total scroll time. I think that 300 000 000 years is close enouth to infinity. if not enought you can restart timer in onFinish()
final int scrollPeriod = 20; // every 20 ms scoll will happened. smaller values for smoother
final int heightToScroll = 20; // will be scrolled to 20 px every time. smaller values for smoother scrolling
listView.post(new Runnable() {
#Override
public void run() {
new CountDownTimer(totalScrollTime, scrollPeriod ) {
public void onTick(long millisUntilFinished) {
listView.scrollBy(0, heightToScroll);
}
public void onFinish() {
//you can add code for restarting timer here
}
}.start();
}
});
Here a few pointers : Simulate onFling() programmatically instead of detecting it (Android)
and Programmatically Fling ListView Android
It's hard to figure out what you call smooth enough in your case. Usually smoothness problems are related to a non optimal usage of listviews and troubles in either cell layouts or view creation / recycling inside the getView method of adapters.
Do you use a placeholder ?
An important thing to consider is also Drawables usage.
I never achieved what you are looking for, but a simple idea that comes to mind is :
find a way to scroll the view of 1 position or 2.
use a ring buffer inside your adapter. For instance let's say you got 100 items in your list of items. Then at the beginning, item 0 of the listview is item 0 of your list. When listview is scrolled up of 1 item, then item 0 of listview should become item 1 in your list. Thus the problem would not be scrolling but more syncing with scrolling and displaying an endless list of items.
My app scrolling is super fast!
How can I limit the scroll speed of a scroll view in my android app?
The scroll can be very fast and it's meaningless to scroll in that speed.
This thread is old, but I will reply with a partial solution: limiting the fling velocity. Feel free to comment so I can improve my solution.
As explained in the Developer Training guide:
Flinging is the type of scrolling that occurs when a user drags and lifts her finger quickly.
That's where I needed a velocity limit. So, in the Custom ScrollView (whether horizontal or vertical)
override fling method like this.
#Override
public void fling(int velocityY) {
int topVelocityY = (int) ((Math.min(Math.abs(velocityY), MAX_SCROLL_SPEED) ) * Math.signum(velocityY));
super.fling(topVelocityY);
}
I found that velocityY (in horizontal scrollview, it would be velocityX) could be between -16000 and 16000. Negative just means scrolling back. I'm still testing this values, and I have tested it in only one device. Not sure if it's the same in older devices/API versions. I will come back later to edit this.
(int) ((Math.min(Math.abs(velocityY), MAX_SCROLL_SPEED) ) * Math.signum(velocityY));
What I'm doing there is obtaining the minimum value between my constant MAX_SCROLL_SPEED and original velocityY, then obtaining the sign of the original velocityY. We need the sign to scroll back.
Finally, sending back the modified velocityY.
It's a partial solution, because if the user keeps pressing the scrollview, the speed won't change.
Again, feel free to improve my answer, I'm still learning.
ObjectAnimator anim = ObjectAnimator.ofInt(mScrollView, "scrollY", mScrollView.getBottom());
anim.setDuration(9000);
anim.start();
I think using timer you can limit the speed of scroll. look at this link Android: HorizontalScrollView smoothScroll animation time
This is how I achieved a smooth vertical scroll (like movie credits). This also allows the user to move the scroll up and down and allow it to continue scrolling when they let go. In my XML, I encapsulated my TextView inside of a ScrollView called "scrollView1". Enjoy!
final TextView tv=(TextView)findViewById(R.id.lyrics);
final ScrollView scrollView = (ScrollView) findViewById(R.id.scrollView1);
Button start = (Button) findViewById(R.id.button_start);
Button stop = (Button) findViewById(R.id.button_stop);
final Handler timerHandler = new Handler();
final Runnable timerRunnable = new Runnable() {
#Override
public void run() {
scrollView.smoothScrollBy(0,5); // 5 is how many pixels you want it to scroll vertically by
timerHandler.postDelayed(this, 10); // 10 is how many milliseconds you want this thread to run
}
};
start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
timerHandler.postDelayed(timerRunnable, 0);
}
});
stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
timerHandler.removeCallbacks(timerRunnable);
}
});
I have a listview with 200 items. I use a custom view for each row. There is a code that takes some time to calculate, and because of this the list hangs out on scrolling and loads in slow (2-3sec).
I have subclassed SimpleCursorAdapter, and using Filterable and SectionIndexer.
I have in mind to show initially the name of the record, and put in a thread the calculation, and will show up later when it's done.
How do I push back some work, and later update the listview to include the calculated data? This should show up on fly without user interaction.
Since android the Android UI is singlethreaded it will be blocked whenever you perform a long operation.
You could do regular java threading and have a Handler() in the main UI class that you can feed back information into. But..
The simplest way would be to create an AsyncTask(). They are java threads with a slight change. They can perform a UI operation before/after the main calculation. So for example:
private class AndroidThread extends AsyncTask {
protected Object doInBackground(Object... params) {
return result;
}
protected void onPostExecute(Object result) {
// do things here with the result of the doInBackground function
// Like: "UiElement"."performTask(result)"
}
}
For more information on AsyncTask see this
Hmm, interesting question. Here are some quick thoughts:
1) Put the values which can be retrieved directly, i.e. the name of the record as you put it, straight into the list. Leave default values, such as "Loading...", for everything that might take a while to compute.
2) Create a second thread to do the calculations, but to make sure it doesn't calculate everything use the ListView's onScrollStateChanged listener. This lets you only do the background work when the list is either idle, or being scrolled slowly by touch-scroll. In other words, don't bother when it's in 'fling' mode since the rows would be long past before the calculations finished.
3) I'm not entirely sure how you can enqueue the loading stage in the thread. You only want to have one loading thread - opening a new thread for each row would be rather messy and also pointless as the phones aren't multicore - but that means the thread has to have a queueing system. What I mean is that the thread has to be aware of what rows are waiting for calculation, but I haven't thought of how you'd do that yet. However, this would also have to be tied to which rows are visible. There's no point in the thread calculating information for rows long past in the list.
4) Whenever the loading thread finishes a particular row, you could call notifyDatasetChanged() on the list adapter. This might get a bit heavy if the ListView tries to refresh its data for every row rather than just those visible, but you'd have to experiment to see.
I hope these ideas help a bit!
In response to the comment: Assuming you're asking when a row is visible, you can do that by implementing ListView.OnScrollListener. I took inspiration from ApiDemos List13, but here are the relevant bits of code:
public class YourClass extends ListActivity implements ListView.OnScrollListener {
public void onCreate(Bundle sIS){
(...)
// Note, you may have to write your own list adapter, extending BaseAdapter
// See List13 in Api Demos for an example if you're not sure how to do that
setListAdapter(yourImageAdapter);
getListView().setOnScrollListener(this);
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
Log.d(LOG_TAG, "onScroll, firstVisibleItem = " + firstVisibleItem +
", visibleItemCount = " + visibleItemCount
+ ", totalItemCount = " + totalItemCount);
}
public void onScrollStateChanged(AbsListView view, int scrollState) {
Log.d(LOG_TAG, "onScrollStateChanged called, scrollState = " + scrollState);
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
int first = view.getFirstVisiblePosition();
int count = view.getChildCount();
Log.d(LOG_TAG, "first = " + first + ", count = " + count);
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
//Scrolling with the finger touching the screen
break;
case OnScrollListener.SCROLL_STATE_FLING:
// User 'threw' the list up or down and it's scrolling rapidly
break;
}
}
}
That tells you everything about your list: whether it's scrolling, what's visible, etc. If you use that with the loading thread to only do the background work for the visible rows, that should help reduce unnecessary overhead.
Another point about BaseAdapter: I haven't tried using any other form of list adapter so maybe it's the same with all of them, but one very useful thing with BaseAdapter is that it lets you handle the 'inflation' of each row individually. Every time the list is about to display a new row, getView is called. You can put custom code in there to do things like put "Loading..." if the information hasn't been calculated yet, or actually display it if it has.
By the way, what are you actually calculating in this list that takes so long?