I am trying to make an animated countdown on android plataform, that show de number 3 in textView growing up from 0 to 1.5 on scale property, so the number 2, 1 and "GO!".
I'm using a textView, an Animation and an AnimationListener, but the animation doesn't work as I want, it works just in first animation showing number 3, so it shows the word "go!" without animating.
What am I doing wrong?
Thanks!
Here the View counter.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_height="fill_parent"
android:layout_width="fill_parent" android:gravity="center_vertical|center_horizontal">
<TextView
android:id="#+id/txtCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3" android:textColor="#ffffff" android:textSize="150dp"/>
</LinearLayout>
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="#android:anim/linear_interpolator"
android:fromXScale="0"
android:toXScale="1.5"
android:fromYScale="0"
android:toYScale="1.5"
android:fillAfter="false"
android:duration="1000" />
</set>
My code:
public class AdivinhacaoActivity extends Activity {
...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//async task
new loaderImages(this).execute();
}
private class loaderImages extends AsyncTask<Void, String, Bitmap[]> {
Activity activity;
public loaderImages(Activity act){
activity = act;
}
protected Bitmap[] doInBackground(Void... arg0) {
...
return list;
}
...
int countCounter;
protected void onPostExecute(Bitmap[] imagens){
bmps = imagens;
carregaContagem();
final Animation anima = AnimationUtils.loadAnimation(activity, R.anim.counter);
countCounter = 3;
anima.setAnimationListener(new AnimationListener() {
public void onAnimationStart(Animation anim){};
public void onAnimationRepeat(Animation anim){};
public void onAnimationEnd(Animation anim)
{
//here I tried txtCount.clearAnimation() but it doesn't work
countCounter--;
if(countCounter >= 0){
//change the text
if(countCounter > 0){
txtCount.setText("" + countCounter);
}
else{
txtCount.setText("GO!");
}
//start animation again with text changed
txtCount.startAnimation(anim);
}
else{
...
}
};
});
//start animation first time
txtCount.startAnimation(anima);
}
}
}
I managed solve my problem, using one textView and one animation instance for each count, yes it works, but I couldn't understand why reason my original solution didn't work!
Related
I'm trying to make a countdown timer in form of a progress bar, and that's what i tried so far: but it don't work at all.
Layout XML File:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/background"
tools:context=".thetest">
<ProgressBar
android:id="#+id/progressBarToday"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="79dp"
android:layout_height="101dp"
android:layout_centerInParent="true"
android:indeterminate="false"
android:max="30"
android:progress="29"
android:progressDrawable="#drawable/circular_progress_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Java:
public class thetest extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thetest);
ProgressBar pb = (ProgressBar) findViewById(R.id.progressBarToday);
Animation an = new RotateAnimation(0.0f, 90.0f, 250f, 273f);
an.setFillAfter(true);
pb.startAnimation(an);
}
}
And finally the drawable style file(not sure if it might help but yeah):
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/progress">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="7.0"
android:useLevel="true">
<gradient
android:startColor="#fb0000"
android:endColor="#00FF00"
android:centerColor="#fbf400"
android:type="sweep" />
</shape>
</item>
</layer-list>
I found the solution:
Xml:
<ProgressBar
android:id="#+id/progressbar"
style="#android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100"
android:progress="0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Java code:
public class thetest extends AppCompatActivity {
ProgressBar mProgressBar;
CountDownTimer mCountDownTimer;
int i=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_thetest);
mProgressBar=findViewById(R.id.progressbar);
mProgressBar.setProgress(i);
mCountDownTimer=new CountDownTimer(30000,1000) {
#Override
public void onTick(long millisUntilFinished) {
Log.v("Log_tag", "Tick of Progress"+ i+ millisUntilFinished);
i++;
mProgressBar.setProgress((int)i*100/(30000/1000));
}
#Override
public void onFinish() {
//Do what you want
i++;
mProgressBar.setProgress(100);
}
};
mCountDownTimer.start();
}
}
Rather than using animation to get a countdown timer, you can programmatically set the countdown time length as maximum progress of ProgressBar, and use a Handler object scheduled to run every second, to update the current progress of the ProgressBar as shown below:
final ProgressBar pb = findViewById(R.id.progressBarToday);
// for eg: if countdown is to go for 30 seconds
pb.setMax(30);
// the progress in our progressbar decreases with the decrement
// in the remaining time for countdown to be over
pb.setProgress(30);
// keep track of current progress
final int[] currentProgress = {30};
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
currentProgress[0] -= 1;
pb.setProgress(currentProgress[0]);
if(currentProgress[0] != 0){
new Handler().postDelayed(this, 1000);
}else
Toast.makeText(requireContext(), "Count Down is OVER!!", Toast.LENGTH_LONG).show();
}
}, 1000);
I've implemented SmoothRefreshLayout library in my application, which has at the moment a simple ListView.
The problem occurs when I scroll down the ListView and, when I try to get to the top of it, instead of scrolling up, it invokes the Refresh listener. So the movement is stuck.
This is the activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<me.dkzwm.widget.srl.SmoothRefreshLayout
android:id="#+id/smoothRefreshLayout"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:indeterminateDrawable="#drawable/circular_spinner" >
</ProgressBar>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/lv"
/>
</RelativeLayout>
</me.dkzwm.widget.srl.SmoothRefreshLayout>
And this is the part of the RefreshListener in the onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setTitle("");
setContentView(R.layout.activity_main);
refreshLayout = (SmoothRefreshLayout)findViewById(R.id.smoothRefreshLayout);
refreshLayout.setHeaderView(new MyCustomHeader(this));
refreshLayout.setEnabled(true);
refreshLayout.setOnRefreshListener(new RefreshingListenerAdapter() {
#Override
public void onRefreshBegin(boolean isRefresh) {
if (isNetworkAvailable(MainActivity2.this)) {
isRef = true;
new upd().execute();
} else {
Toast.makeText(MainActivity2.this, getResources().getString(R.string.err_conn), Toast.LENGTH_SHORT).show();
}
}
});
I know it has no sense to self reply, but it may help someone else.
Anyway, the solution has been simple, I have just implemented an onScrollListener and checked if first item was on the top, if not just disable the Refresher.
listView.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
public void onScroll(AbsListView listView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int rowpos = (listView == null || listView.getChildCount() == 0) ?
0 : listView.getChildAt(0).getTop();
refreshLayout.setEnabled((rowpos >= 0));
}
});
Credits: Can't scroll in a ListView in a swipeRefreshLayout
I've already checked this SO post but to no avail: removeCallbacks not stopping runnable
What my app does: I have 2 imageViews. When app runs, one imageView should change it's image from sleep image to wake up image and then back to sleep image. Then handler used for delay before doing same thing for 2nd imageView. And then I want Runnable to stop. I'm using Android's frame animation.
Please help!
public class MainActivity extends Activity {
AnimationDrawable[] animDrawList;
ImageView im;
ImageView im2;
private int curPos;
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
animDrawList = new AnimationDrawable[2];
curPos = 0;
im = (ImageView)findViewById(R.id.image1);
im2 = (ImageView)findViewById(R.id.image2);
im.setBackgroundResource(R.drawable.animation_to_run);
im2.setBackgroundResource(R.drawable.animation_to_run);
animDrawList[0] = (AnimationDrawable) im.getBackground();
animDrawList[1] = (AnimationDrawable) im2.getBackground();
mHandler = new Handler();
startTask();
}
Runnable myThread = new Runnable() {
volatile boolean stopMe = false;
#Override
public void run() {
if ( curPos <= 1 ) {
animDrawList[curPos].start();
curPos++;
}
if ( curPos > 1 ) {
stopMe = true;
}
if ( stopMe ) {
stopTask();
return;
}
mHandler.postDelayed(myThread, 1000);
}
};
void startTask() { myThread.run(); }
void stopTask() { mHandler.removeCallbacks(myThread); }
}//end of MainActivity class
Here is my layout file that's straighforward :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.example.a.MainActivity">
<ImageView
android:id="#+id/image1"
android:layout_width="90px"
android:layout_height="90px"
android:layout_alignParentStart="true"
android:layout_marginStart="14dp"
android:layout_marginTop="13dp" />
<ImageView
android:id="#+id/image2"
android:layout_width="90px"
android:layout_height="90px"
android:layout_marginEnd="49dp"
android:layout_marginBottom="93dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
Here is my xml file.
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/restState" android:duration="1000" />
<item android:drawable="#drawable/upState" android:duration="1000" />
<item android:drawable="#drawable/restState" android:duration="1000" />
</animation-list>
The app runs, no crashes, but it doesn't stop. I want the Runnable to stop after animating, why isn't my flag "stopMe" doing it's job?
UPDATE FROM JUN 4, 2017: I removed the animation code inside the run method and and added logcat output insted in run method and Runnable does stop with "stopMe" boolean so it's issue with the frame animation, is it I can't combine Android's frame animation with Runnable? I'll look into it...
you just need to add a condition in the run method
public void run() {
while(!stopMe)
{
if ( curPos <= 1 ) {
animDrawList[curPos].start();
curPos++;
}
if ( curPos > 1 ) {
stopMe = true;
}
if ( stopMe ) {
stopTask();
return;
}
mHandler.postDelayed(myThread, 1000);
}
}
I've solved it! I had to set the AnimationDrawable object's setOneShow(boolean playAnimationOncePerAnimationDrawableObject) to true! Voila!
I have android view that I want to fadeIn and Fadeout when users click on a button. The animation itself is being called and the callback is being called but when the animation triggers the view cannot be seen. I think the problem is with the xml layout, I have been stuck on this for hours if someone can help it would be greatly appreciated.
My Main Layout: - Just view in question
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="left|top"
android:background="#color/whiteOverlay"
android:gravity="center_vertical|center_horizontal"
android:id="#+id/uploadOptions"
android:alpha="0"
android:visibility="gone">
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="40dp"
android:paddingRight="40dp">
<Button
style = "#style/basic_button"
android:text="#string/selectFromGallery"
android:id="#+id/gallery_select"
android:layout_marginTop="10dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<Button
style = "#style/basic_button"
android:text="#string/selectFromCamera"
android:id="#+id/camera_select"
android:layout_marginTop="10dp"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
</LinearLayout>
FadeIn
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:duration="500" />
</set>
FadeOut
<?xml version="1.0" encoding="UTF-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:interpolator="#android:anim/accelerate_interpolator"
android:duration="500" />
</set>
Activity Java -
public class regPP extends Activity {
private String lang = "";
private Boolean optionsActive = false;
private LinearLayout options = null;
private void fade (final View view, final Boolean Toggle){
Animation anim;
view.setVisibility(View.VISIBLE);
if(Toggle){
//fadeOut
anim = AnimationUtils.loadAnimation(regPP.this, R.anim.fadeout);
Log.d("FADE","FadeOut");
} else {
//fadeIn
anim = AnimationUtils.loadAnimation(regPP.this, R.anim.fadein);
Log.d("FADE","FadeIn");
}
view.startAnimation(anim);
anim.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation arg0) {
//Functionality here
if(Toggle){
view.setVisibility(View.GONE);
Log.d("FADE", "FadeOut Callback");
} else {
view.setVisibility(View.VISIBLE);
Log.d("FADE", "FadeIn Callback");
}
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
}
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.lang = getResources().getString(R.string.lang);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
final Context context = regPP.this;
setContentView(R.layout.reg_pp);
ImageButton uploadTog = (ImageButton) findViewById(R.id.uploadTog);
options = (LinearLayout) findViewById(R.id.uploadOptions);
uploadTog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fade(options,false);
optionsActive = true;
}
});
}
#Override
public void onBackPressed() {
if(optionsActive){
fade(options,true);
optionsActive = false;
} else {
super.onBackPressed();
}
}
}
remove this line may help u
android:visibility="gone"
visibility is gone that's why your view is not visible
android:visibility="gone"
I am building an application which display a map (the map is the canvas background) and localise users by adding circle on the canvas(using draw circle). I would like to add a button over the canvas(for now a draw a button on the map and check with ontouch() if the user clicked on it) and when the button is touched I would like to have a window popup. It worked but the popup is behind the canvas(I could see a small piece of it(I removed it)).Is there a way to have my canvas BEHIND the button and the popup window? I saw people talking about putting the canvas in relative layout but I have no idea how to do that.
Here is the xml of my activity, really simple:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#drawable/umap2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Button" />
</RelativeLayout>
And here is my activity java code(I removed a couple of things that doesnt have nothing to do with my problem)
package com.example.client;
import java.util.LinkedList;
//....
import java.util.Timer;
public class Campus extends Activity{
final Handler myHandler = new Handler();
MapView mapv;
final Activity self = this;
Float ratioX;
Float ratioY;
int width;
int height;
static boolean out=false;
Intent i;
//creating a linked list for each hall
static LinkedList<compMac> DMS = new LinkedList<compMac>();
static LinkedList<compMac> MCD = new LinkedList<compMac>();
//...
static LinkedList<compMac> SCI = new LinkedList<compMac>();
static LinkedList<compMac> STE = new LinkedList<compMac>();
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.campus);
setSize();
this.mapv = new MapView(this);//!! my view
setContentView(mapv);
i= new Intent(this, myService.class);
this.startService(i);
}
//*******************************View class!*******************************
public class MapView extends View {
/*
* Extract the connected users and location from the array. separate the
* array into an array for each building
* */
private Paint redPaint;
private float radius;
Canvas canvas;
public MapView(Context context) {
super(context) ;
redPaint = new Paint();
redPaint.setAntiAlias(true);
redPaint.setColor(Color.RED);
redPaint.setTextSize(10);
}
#Override
//drawing a point on every hall on the map where users are connected
public void onDraw (Canvas canvas) {
// draw your circle on the canvas
if(!out)
{
AlertDialog.Builder outOfCampus = new AlertDialog.Builder(self);
outOfCampus.setTitle("Sorry");
outOfCampus.setMessage("You are out of Campus");//(toDisplay);
outOfCampus.setCancelable(false);
outOfCampus.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
startActivity(new Intent("com.example.client.Sin"));
}});
AlertDialog alertdialog = outOfCampus.create();
outOfCampus.show();
}
this.canvas=canvas;
setBackgroundResource(R.drawable.umap2);
}
public void drawPoints(LinkedList<compMac> building)
{
if(!building.isEmpty())
{
while(!building.isEmpty())
{
compMac current = building.pop();
Float x= ratioX*(Float.parseFloat(current.getCoorX()));
Float y= ratioY*(Float.parseFloat(current.getCoorY()));
// Log.w("ratioX ",(((Double)(width/768)).toString()));
// Log.w("ratioY ",(float)(y.toString()));
canvas.drawCircle (x,y, 10, redPaint);
}
}
}
public boolean onTouchEvent (MotionEvent event) {
//...//
return true;
}
}
}
Someone have an idea how i can do that? Thanks
Calling setContentView two times would not work. Instead you should put your canvas view and the button in a single layout itself but with proper ordering. The last widget in the relative layout gets more priority, so if you want the button to come on top of the canvas your layout should be something like this.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#drawable/umap2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.example.client.MapView
android:id="#+id/mapView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:text="Button" />
</RelativeLayout>
And to access your MapView in java class
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.campus);
setSize();
this.mapv = findViewById(R.id.mapView); //!! my view
i= new Intent(this, myService.class);
this.startService(i);
}
And obviously alert dialog will be on top of the canvas. Hope it helps!
Edit: I think inflate error is due to incorrect class path. Since MapView is inner class of Campus, path should be like this
<com.example.client.Campus.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Also add this constructor to your MapView class
public MapView(Context context, AttributeSet attributeSet) {
super(context, attributeSet) ;
redPaint = new Paint();
redPaint.setAntiAlias(true);
redPaint.setColor(Color.RED);
redPaint.setTextSize(10);
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="#drawable/umap2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:id="#+id/btn_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="#drawable/back_transparent_pressed" >
<Button
android:id="#+id/button1"
android:layout_centerInParent="true"
/>
</RelativeLayout>