I have an ImageView, an ArrayList and a Button. My ArrayList has multiple numbers. For example 1,2,2,4,3. When i push the button, i want to animate the ImageView with the numbers inside ArrayList.
According to sample ArrayList. ArrayList[0]=1 ImageView will animate up, ArrayList[1]=2 ImageView will animate down. The animation will continue with all ArrayList inside. To do this, i have to use "for loop".
But the animation does not continue, the animation loop does not work. Only ArrayList[0] is working and then stop.`When i push the button second time, ArrayList[2] is working the stop. I have to push the button all the time for working all ArrayList. I want to push the button one time and i want to work all ArrayList.
//imageViewPlay=button hareketler=ArrayList imageViewMario=ImageView
imageViewPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i=0;i<hareketler.size();i++){
if (hareketler.get(0)==1){
imageViewMario.animate().y(imageViewMario.getY() -imageViewEngel.getHeight()-7).setDuration(2000).withEndAction(new Runnable() {
#Override
public void run() {
hareketler.remove(0);
}
});
}
if (hareketler.get(0)==2){
imageViewMario.animate().y(imageViewMario.getY() +imageViewEngel.getHeight()+7).setDuration(2000).withEndAction(new Runnable() {
#Override
public void run() {
hareketler.remove(0);
}
});
}
if (hareketler.get(0)==3){
imageViewMario.animate().x(imageViewMario.getX() +imageViewEngel.getHeight()+7).setDuration(2000).withEndAction(new Runnable() {
#Override
public void run() {
hareketler.remove(0);
}
});
}
if (hareketler.get(0)==4){
imageViewMario.animate().x(imageViewMario.getX() -imageViewEngel.getHeight()-7).setDuration(2000).withEndAction(new Runnable() {
#Override
public void run() {
hareketler.remove(0);
}
});
}
}
}
});
'Only ArrayList[0] is working and then stop' That is because you hardcoded this line with the value 0 :
if (hareketler.get(0)==...)
this will always only get the first item of your array.
You are incrementing your for loop, but not the positions that you are getting from the array.
if (hareketler.get(i)==...)
that will use the i value of the for loop to also increment the position of your array.
And then of course :
hareketler.remove(i)
This is because withEndAction is not a synchronous call and for did not wait for the first animation to end. What you need is recursive function which will be called again on animation end. Like this:
private void playAnimation(){
if (hareketler.get(0)==1){
imageViewMario.animate().y(imageViewMario.getY() -imageViewEngel.getHeight()-7).setDuration(2000).withEndAction(runnable);
}else if .... and so on
Also create a runnable which will call the method again on animation end
private Runnable runnable = new Runnable() {
#Override
public void run() {
hareketler.remove(0);
playAnimation()
}
};
And in your click listener:
imageViewPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playAnimation()
}
});
Hope this will work.
Related
I have a function to programatically display messages in a scroll view by adding textviews to the linearlayout in it.
I want it to be inside a handler.post, and also want the scrollview to automatically scroll to the bottom of the scrollview every time a message is added.
Here is the code:
public void addMsg(final String msg) {
handler.post(new Runnable() {
#Override
public void run() {
TextView newText = new TextView(getApplicationContext());
newText.setText(msg);
linLayout.addView(newText);
scrollView.post(new Runnable() {
#Override
public void run() {
scrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
});
}
Is it bad convention to do this? Is there another way to accomplish this without nested runnables if it is bad to do?
I have developed an app in which I have a textview whose text keeps scrolling automatically. I also have an imageview whose image keeps changing automatically after every four seconds. To accomplish this I have created a new runnable having 4 seconds time. Suppose there are 5 images which gets displayed. The problem is every time a new image is loaded in imageview the text of textview gets reset and it starts scrolling from beginning and this happens only for the first iteration of all the images. After all images are displayed once then from the next iteration onwards the textview starts behaving properly and the text doesn't resets. I don't know what is the problem. Here is the code
//In onCreate
headlinesText = (TextView) findViewById(R.id.text_news);
headlinesText.setSelected(true);
//This is a separate method
public void settingAds() {
myRef.child("Advertisements").addValueEventListener(new com.google.firebase.database.ValueEventListener() {
#Override
public void onDataChange(com.google.firebase.database.DataSnapshot dataSnapshot) {
imageUrl.clear();
for (com.google.firebase.database.DataSnapshot eachAdUrl : dataSnapshot.child("Adurls").getChildren()) {
imageUrl.add(String.valueOf(eachAdUrl.getValue()));
}
headlineFromFirebase = String.valueOf(dataSnapshot.child("News").getValue());
adTimer = (long) dataSnapshot.child("Time").getValue();
headlinesText.setText(headlineFromFirebase);
/*headlinesText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, NewsList.class));
}
});*/
//Randomly shuffling the array list
Collections.shuffle(imageUrl);
for(int i=0;i<imageUrl.size();i++) {
Picasso.with(MainActivity.this)
.load(imageUrl.get(i))
.fetch();
}
//runnable code was here
if(handler != null) {
handler.removeCallbacks(runnable);
}
handler = new Handler();
runnable = new Runnable() {
int imageCounter=0;
public void run() {
Picasso.with(MainActivity.this)
.load(imageUrl.get(imageCounter))
.fit()
.centerCrop()
.into(mAdsView);
imageCounter++;
if (imageCounter > imageUrl.size()-1) {
imageCounter = 0;
}
handler.postDelayed(this,adTimer);
}
};
handler.postDelayed(runnable, 250);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
My problem is pretty simple. I am creating a card based on the result of a HTTP query performed inside a separate thread. The card also has an onclick method and is defined inside a runOnUiThread() located inside the separate thread. However, when the device is tapped, the onclick event isn't fired.
Here is my code:
private void login() {
Runnable r = new Runnable() {
#Override
public void run() {
// irrelevant code
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(buildError(code));
}
}
}
Thread t = new Thread(r);
t.start();
}
private View buildError(String code) {
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.ALERT);
card.setIcon(R.drawable.ic_warning_150);
if (code.equals("1"))
card.setText("Incorrect credientals");
else
card.setText("Unexpected error");
card.setFootnote("Tap to try again");
View cView = card.getView();
cView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Event", "Clicked"); // This is what isn't triggering
}
});
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
return cView;
}
Even though the snippet of code contains an error (can't be compiled, missing ; at the Runnable statement), you were on the right track.
The View simply needs to request the focus in order to be clickable right away. Otherwise you'll have to move the focus manually.
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
cView.requestFocus();
Reference
I've seen some similar questions and got some information but they stop shy of telling me enough to get it working.
What I'm trying to do is make a simple rhythm game where the player taps a button at regular intervals (ie. beats). I wanted to set up a way of signalling when to tap by having the button change colour, and since this would be a repeated task at regular intervals I want to use a timer object with a schedule method.
But when I try calling on this method it tells me that I can't change the UI in a non UI thread. I've tried a few ways to write a method in the main thread that I can call from the timer object but I get the same error every time. I'm assuming that I just have the wrong idea about what counts as being from the UI thread, so I was hoping someone could clear it up.
Here's a snippet of one way I tried it, just to show what my code looks like:
OnClickListener clickButton = new View.OnClickListener() {
public void onClick(View v) {
if (startBeat == 0){
startBeat = System.nanoTime();
timerStart.scheduleAtFixedRate((new TimerTask()
{
public void run()
{
flashButton();
}
}), 0, beatTime);
timerEnd.schedule(new TimerTask()
{
public void run()
{
unflashButton();
}
}, beatTolerance*2, beatTime);
return;
}
};
public void flashButton(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
public void unflashButton(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
}
To be clear, this is all contained within my MainActivity class along with the OnCreate class.
if you are in an activity all you need to do is use runOnUiThread() and then place the code to change the ui element in there
public void flashButton(){
runOnUiThread(new Runnable() {
#Override
public void run() {
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
});
}
You cannot, under any circumstances, touch a UI object from a non UI thread.
You can accomplish your intent using Handler.sendMessageDelayed
UI can only be touched by the main thread. You should post the actions you are performing on the ui thread via handler or via runOnUiThread
Try something similar to this
timerStart.scheduleAtFixedRate((new TimerTask()
{
public void run()
{
//replace MainActivity with your activity
//if inside a fragment use getActivity()
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
flashButton();
}
});
}
}), 0, beatTime);
If you are in an Activity you could surround flashButton() with an runOnUiThread.
...
runOnUiThread(new Runnable(){
public void run(){
flashButton();
}
});
...
use android.os.Handler Class. Change your code as follows:
private Handler handler=new Handler();
public void flashButton(){
handler.post(new Runnable(){
public void run(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1transparent_very));
}
});
}
public void unflashButton(){
handler.post(new Runnable(){
public void run(){
beatPrompt.setBackgroundColor(getResources().getColor(R.color.primary1));
}
});
}
So I have some simple code but it seems to not be working.. any suggestions?
I just want an image to show after a button is pressed then become invisible after 2 seconds.
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
// delay of some sort
firstImage.setVisibility(ImageView.INVISIBLE);
}
}
The image never shows, it always stays invisible, should I be implementing this in another way? I've tried handlers.. but it didn't work, unless I did it wrong.
Never make your UI thread sleep!
Do this:
final Handler handler = new Handler();
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
handler.postDelayed(new Runnable(){
public void run(){
firstImage.setVisibility(ImageView.INVISIBLE);
}
}, DELAY);
}
}
Where you would set DELAY as 2000 (ms).
Well, you will need to add a delay between the two lines. Use a thread or a timer to do this.
Start a thread on click of a button. In the run method, change the ImageView's visibility to VISIBLE, then put the thread to sleep for n secs, and then change then make it invisible.
To call the imageView's setvisibility method, you will need a hanlder here.
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
image.setVisibiliy(VISIBLE);
Thread.sleep(200);
image.setVisibility(INVISIBLE);
}
});
I know this question has already been answered, but I thought I would add an answer for people who like me, stumbled across this looking for a similar result where the delay was caused by a process rather than a "sleep"
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
firstImage.setVisibility(ImageView.VISIBLE);
// Run the operation on a new thread
new Thread(new Runnable(){
public void run(){
myMethod();
returnVisibility();
}
}).start();
}
}
private void myMethod() {
// Perform the operation you wish to do before restoring visibility
}
private void returnVisibility() {
// Restore visibility to the object being run on the main UI thread.
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
firstImage.setVisibility(ImageView.INVISIBLE);
}
});
}