A circular status of a countdown timmer [duplicate] - java

I am trying to create a rounded progressbar. This is what I want to achieve
There is a grey color background ring. On top of it, a blue color progressbar appears which moves in a circular path from 0 to 360 in 60 or whatever amount of seconds.
Here is my example code.
<ProgressBar
android:id="#+id/ProgressBar"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?android:attr/progressBarStyleLarge"
android:indeterminateDrawable="#drawable/progressBarBG"
android:progress="50"
/>
To do this, in the drawable "progressBarBG", I am creating a layerlist and inside that layer list I am giving two items as shown.
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/background">
<shape
android:shape="ring"
android:innerRadius="64dp"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="#color/grey" />
</shape>
</item>
<item android:id="#android:id/progress">
<clip>
<shape
android:shape="ring"
android:innerRadius="64dp"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="#color/blue" />
</shape>
</clip>
</item>
Now, the first grey ring is generated fine. The blue ring however starts from the left of the drawable and goes to the right just like how a linear progressbar works. This is how it shows at 50% progress with the red color arrow showing direction.
I want to move the blue progressbar in circular path as expected.

Here are my two solutions.
Short answer:
Instead of creating a layer-list, I separated it into two files. One for ProgressBar and one for its background.
This is the ProgressDrawable file (#drawable folder): circular_progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="1dp"
android:useLevel="true"><!-- this line fixes the issue for lollipop api 21 -->
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>
And this is for its background(#drawable folder): circle_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="1dp"
android:useLevel="false">
<solid android:color="#CCC" />
</shape>
And at the end, inside the layout that you're working:
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="200dp"
android:layout_height="200dp"
android:indeterminate="false"
android:progressDrawable="#drawable/circular_progress_bar"
android:background="#drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="65" />
Here's the result:
Long Answer:
Use a custom view which inherits the android.view.View
Here is the full project on github

With the Material Components Library you can use the CircularProgressIndicator:
Something like:
<com.google.android.material.progressindicator.CircularProgressIndicator
app:indicatorColor="#color/...."
app:trackColor="#color/...."
app:indicatorSize="64dp"/>
You can use these attributes:
indicatorSize: defines the radius of the circular progress indicator
trackColor: the color used for the progress track. If not defined, it will be set to the indicatorColor and apply the android:disabledAlpha from the theme.
indicatorColor: the single color used for the indicator in determinate/indeterminate mode. By default it uses theme primary color
Use progressIndicator.setProgressCompat((int) value, true); to update the value in the indicator.
Note: it requires at least the version 1.3.0-alpha04.

I have done with easy way:
Please check screen shot for the same.
CustomProgressBarActivity.java:
public class CustomProgressBarActivity extends AppCompatActivity {
private TextView txtProgress;
private ProgressBar progressBar;
private int pStatus = 0;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_progressbar);
txtProgress = (TextView) findViewById(R.id.txtProgress);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
new Thread(new Runnable() {
#Override
public void run() {
while (pStatus <= 100) {
handler.post(new Runnable() {
#Override
public void run() {
progressBar.setProgress(pStatus);
txtProgress.setText(pStatus + " %");
}
});
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
pStatus++;
}
}
}).start();
}
}
activity_custom_progressbar.xml:
<RelativeLayout 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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.skholingua.android.custom_progressbar_circular.MainActivity" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:layout_height="wrap_content">
<ProgressBar
android:id="#+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:progressDrawable="#drawable/custom_progressbar_drawable"
android:secondaryProgress="0" />
<TextView
android:id="#+id/txtProgress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#+id/progressBar"
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
</RelativeLayout>
custom_progressbar_drawable.xml:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="-90"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270" >
<shape
android:shape="ring"
android:useLevel="false" >
<gradient
android:centerY="0.5"
android:endColor="#FA5858"
android:startColor="#0099CC"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>
Hope this will help you.

I have written detailed example on circular progress bar in android here on my blog demonuts.com. You can also fond full source code and explanation there.
Here's how I made circular progressbar with percentage inside circle in pure code without any library.
first create a drawable file called circular.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#android:id/secondaryProgress">
<shape
android:innerRadiusRatio="6"
android:shape="ring"
android:thicknessRatio="20.0"
android:useLevel="true">
<gradient
android:centerColor="#999999"
android:endColor="#999999"
android:startColor="#999999"
android:type="sweep" />
</shape>
</item>
<item android:id="#android:id/progress">
<rotate
android:fromDegrees="270"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270">
<shape
android:innerRadiusRatio="6"
android:shape="ring"
android:thicknessRatio="20.0"
android:useLevel="true">
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
<gradient
android:centerColor="#00FF00"
android:endColor="#00FF00"
android:startColor="#00FF00"
android:type="sweep" />
</shape>
</rotate>
</item>
</layer-list>
Now in your activity_main.xml add following:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:background="#color/dialog"
tools:context="com.example.parsaniahardik.progressanimation.MainActivity">
<ProgressBar
android:id="#+id/circularProgressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="250dp"
android:layout_height="250dp"
android:indeterminate="false"
android:max="100"
android:progress="50"
android:layout_centerInParent="true"
android:progressDrawable="#drawable/circular"
android:secondaryProgress="100"
/>
<ImageView
android:layout_width="90dp"
android:layout_height="90dp"
android:background="#drawable/whitecircle"
android:layout_centerInParent="true"/>
<TextView
android:id="#+id/tv"
android:layout_width="250dp"
android:layout_height="250dp"
android:gravity="center"
android:text="25%"
android:layout_centerInParent="true"
android:textColor="#color/colorPrimaryDark"
android:textSize="20sp" />
</RelativeLayout>
In activity_main.xml I have used one circular image with white background to show white background around percentage. Here is the image:
You can change color of this image to set custom color around percentage text.
Now finally add following code to MainActivity.java :
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.animation.DecelerateInterpolator;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
int pStatus = 0;
private Handler handler = new Handler();
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Resources res = getResources();
Drawable drawable = res.getDrawable(R.drawable.circular);
final ProgressBar mProgress = (ProgressBar) findViewById(R.id.circularProgressbar);
mProgress.setProgress(0); // Main Progress
mProgress.setSecondaryProgress(100); // Secondary Progress
mProgress.setMax(100); // Maximum Progress
mProgress.setProgressDrawable(drawable);
/* ObjectAnimator animation = ObjectAnimator.ofInt(mProgress, "progress", 0, 100);
animation.setDuration(50000);
animation.setInterpolator(new DecelerateInterpolator());
animation.start();*/
tv = (TextView) findViewById(R.id.tv);
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (pStatus < 100) {
pStatus += 1;
handler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
mProgress.setProgress(pStatus);
tv.setText(pStatus + "%");
}
});
try {
// Sleep for 200 milliseconds.
// Just to display the progress slowly
Thread.sleep(8); //thread will take approx 1.5 seconds to finish
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
If you want to make horizontal progressbar, follow this link, it has many valuable examples with source code:
http://www.skholingua.com/android-basic/user-interface/form-widgets/progressbar

I realized a Open Source library on GitHub CircularProgressBar that does exactly what you want the simplest way possible:
USAGE
To make a circular ProgressBar add CircularProgressBar in your layout XML and add CircularProgressBar library in your projector or you can also grab it via Gradle:
compile 'com.mikhaellopez:circularprogressbar:1.0.0'
XML
<com.mikhaellopez.circularprogressbar.CircularProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:background_progressbar_color="#FFCDD2"
app:background_progressbar_width="5dp"
app:progressbar_color="#F44336"
app:progressbar_width="10dp" />
You must use the following properties in your XML to change your CircularProgressBar.
Properties:
app:progress (integer) >> default 0
app:progressbar_color (color) >> default BLACK
app:background_progressbar_color (color) >> default GRAY
app:progressbar_width (dimension) >> default 7dp
app:background_progressbar_width (dimension) >> default 3dp
JAVA
CircularProgressBar circularProgressBar = (CircularProgressBar)findViewById(R.id.yourCircularProgressbar);
circularProgressBar.setColor(ContextCompat.getColor(this, R.color.progressBarColor));
circularProgressBar.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundProgressBarColor));
circularProgressBar.setProgressBarWidth(getResources().getDimension(R.dimen.progressBarWidth));
circularProgressBar.setBackgroundProgressBarWidth(getResources().getDimension(R.dimen.backgroundProgressBarWidth));
int animationDuration = 2500; // 2500ms = 2,5s
circularProgressBar.setProgressWithAnimation(65, animationDuration); // Default duration = 1500ms
Fork or Download this library here >> https://github.com/lopspower/CircularProgressBar

Here is a simple customview for display circle progress. You can modify and optimize more to suitable for your project.
class CircleProgressBar #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val backgroundWidth = 10f
private val progressWidth = 20f
private val backgroundPaint = Paint().apply {
color = Color.LTGRAY
style = Paint.Style.STROKE
strokeWidth = backgroundWidth
isAntiAlias = true
}
private val progressPaint = Paint().apply {
color = Color.RED
style = Paint.Style.STROKE
strokeWidth = progressWidth
isAntiAlias = true
}
var progress: Float = 0f
set(value) {
field = value
invalidate()
}
private val oval = RectF()
private var centerX: Float = 0f
private var centerY: Float = 0f
private var radius: Float = 0f
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
centerX = w.toFloat() / 2
centerY = h.toFloat() / 2
radius = w.toFloat() / 2 - progressWidth
oval.set(centerX - radius,
centerY - radius,
centerX + radius,
centerY + radius)
super.onSizeChanged(w, h, oldw, oldh)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawCircle(centerX, centerY, radius, backgroundPaint)
canvas?.drawArc(oval, 270f, 360f * progress, false, progressPaint)
}
}
Example using
xml
<com.example.androidcircleprogressbar.CircleProgressBar
android:id="#+id/circle_progress"
android:layout_width="200dp"
android:layout_height="200dp" />
kotlin
class MainActivity : AppCompatActivity() {
val TOTAL_TIME = 10 * 1000L
override fun onCreate(savedInstanceState: Bundle?) {
...
timeOutRemoveTimer.start()
}
private var timeOutRemoveTimer = object : CountDownTimer(TOTAL_TIME, 10) {
override fun onFinish() {
circle_progress.progress = 1f
}
override fun onTick(millisUntilFinished: Long) {
circle_progress.progress = (TOTAL_TIME - millisUntilFinished).toFloat() / TOTAL_TIME
}
}
}
Result

I'm new so I can't comment but thought to share the lazy fix. I use Pedram's original approach as well, and just ran into the same Lollipop issue. But alanv over in another post had a one line fix. Its some kind of bug or oversight in API21. Literally just add android:useLevel="true" to your circle progress xml. Pedram's new approach is still the proper fix, but I just thought I share the lazy fix as well.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="#+id/progress_circular_id"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerInParent="true"
android:indeterminate="false"
android:progress="30"
android:progressDrawable="#drawable/circular_progress_bar"
android:background="#drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100">
</ProgressBar>
<TextView
android:id="#+id/textview_progress_status_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="50%"
android:layout_centerInParent="true"
android:textStyle="bold"
android:textColor="#color/blue"
android:textSize="35dp">
</TextView>
<Button
android:id="#+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="click me"
android:textColor="#color/white"
android:layout_below="#+id/progress_circular_id"
android:layout_centerHorizontal="true"
>
</Button>
</RelativeLayout>
Create a Drawable File with name circle_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:innerRadiusRatio="2.5"
android:thickness="25dp"
android:useLevel="false">
<solid android:color="#CCC" />
</shape>
Create a file with circular_progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="25dp"
android:useLevel="true"><!-- this line fixes the issue for lollipop api 21 -->
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>
In java File For example purpose used fragmet.
public class FragmentRegistration extends BaseFragmentHelper {
View registrationFragmentView;
ProgressBar progressBar;
Button button;
int count=0;
#Override
public void onAttachFragment(#NonNull Fragment childFragment) {
super.onAttachFragment(childFragment);
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
registrationFragmentView = inflater.inflate(R.layout.new_device_registration, container, false);
progressBar=(ProgressBar)registrationFragmentView.findViewById(R.id.progress_circular_id);
button=(Button) registrationFragmentView.findViewById(R.id.check);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
count=count+10;
progressBar.setProgress(count);
}
});
return registrationFragmentView;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onDetach() {
super.onDetach();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public void onDestroyView() {
super.onDestroyView();
}
}

try this method to create a bitmap and set it to image view.
private void circularImageBar(ImageView iv2, int i) {
Bitmap b = Bitmap.createBitmap(300, 300,Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(b);
Paint paint = new Paint();
paint.setColor(Color.parseColor("#c4c4c4"));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(150, 150, 140, paint);
paint.setColor(Color.parseColor("#FFDB4C"));
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.FILL);
final RectF oval = new RectF();
paint.setStyle(Paint.Style.STROKE);
oval.set(10,10,290,290);
canvas.drawArc(oval, 270, ((i*360)/100), false, paint);
paint.setStrokeWidth(0);
paint.setTextAlign(Align.CENTER);
paint.setColor(Color.parseColor("#8E8E93"));
paint.setTextSize(140);
canvas.drawText(""+i, 150, 150+(paint.getTextSize()/3), paint);
iv2.setImageBitmap(b);
}

#Pedram, your old solution works actually fine in lollipop too (and better than new one since it's usable everywhere, including in remote views) just change your circular_progress_bar.xml code to this:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="1dp"
android:useLevel="true"> <!-- Just add this line -->
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep"
android:useLevel="false" />
</shape>
</rotate>

https://github.com/passsy/android-HoloCircularProgressBar is one example of a library that does this. As Tenfour04 stated, it will have to be somewhat custom, in that this is not supported directly out of the box. If this library doesn't behave as you wish, you can fork it and modify the details to make it work to your liking. If you implement something that others can then reuse, you could even submit a pull request to get that merged back in!

Change
android:useLevel="false"
to
android:useLevel="true"
for second sahpe with id="#android:id/progress
hope it works

package com.example.ankitrajpoot.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
private ProgressBar spinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
spinner=(ProgressBar)findViewById(R.id.progressBar);
spinner.setVisibility(View.VISIBLE);
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/loadingPanel"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:id="#+id/progressBar"
android:layout_width="48dp"
style="?android:attr/progressBarStyleLarge"
android:layout_height="48dp"
android:indeterminateDrawable="#drawable/circular_progress_bar"
android:indeterminate="true" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="1080">
<shape
android:shape="ring"
android:innerRadiusRatio="3"
android:thicknessRatio="8"
android:useLevel="false">
<size
android:width="56dip"
android:height="56dip" />
<gradient
android:type="sweep"
android:useLevel="false"
android:startColor="#android:color/transparent"
android:endColor="#1e9dff"
android:angle="0"
/>
</shape>
</rotate>

Good news is that now material design library supports determinate circular progress bars too:
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
For more info about this refer here.

if you want to set progress in an anti-clock direction then use below image for set fromDegree and toDegree's values in progressDrawble xml.
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="-90">
<shape
android:innerRadiusRatio="2"
android:shape="ring"
android:thickness="1dp">
<gradient
android:angle="0"
android:endColor="#007DD6"
android:startColor="#007DD6"
android:type="sweep" />
</shape>
</rotate>
This code will let your progress anti-clockwise and from the top.
Change the degrees as per the above image from where you want to rotate your progress bar.

You can use this library https://github.com/xYinKio/ArcCircleProgressBar
This is one of the most flexible circular progress bars
This picture is showing the lib powers

Related

Button's background isn't displayed

Background isn't displayed. If the button hasn't background, it displayed OK
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="?attr/colorBackgroundFloating"
tools:context=".MainActivity"
tools:layout_editor_absoluteY="25dp">
<Button
android:id="#+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_weight="1"
android:background="#drawable/my_round_button"
android:onClick="onClick"
android:text="#string/button_1"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
When app button hasn't background, button looks like ractangle
my_round_button
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring">
<solid android:color="#FFFFFF" />
</shape>
What's wrong?
Button should looks like ring
A picture is worth a thousand words
So in your case to create a ring shape:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="80dp"
android:shape="ring"
android:thickness="5dp"
android:useLevel="false">
<solid android:color="#FFF" />
<size
android:width="200dp"
android:height="200dp" />
</shape>
You can change innerRadius, thickness, size property based on your UI requirements.
problem is in your shape.
for example you can change your shape to:
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="15dp"
android:thickness="10dp"
android:useLevel="false"
android:shape="ring"
>
<solid android:color="#FFFFFF" />
</shape>
I would recommend you to create custom view, which render the view in form of Circle and as per width/height we pass from the layout. It's more dynamic.
I did like the answer suggested by Son Truong but that seems not more generic as we need to hard code the size width/height.
Step 1: Create a theme in style.xml
<declare-styleable name="CircleCompatTextView">
<attr name="cctv_stroke_width" format="dimension" />
<attr name="cctv_background_color" format="color" />
<attr name="cctv_border_color" format="color" />
</declare-styleable>
Step 2: Create a custom view.
public class CircleCompatTextView extends AppCompatTextView {
private final Paint paintCircle = new Paint();
private final Paint paintStroke = new Paint();
private final Resources resources;
private int strokeWidth;
private int bgColor;
private int borderColor;
private int cxCy;
public CircleCompatTextView(Context context, AttributeSet attrs) {
super(context, attrs);
resources = context.getResources();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleCompatTextView);
strokeWidth = a.getDimensionPixelSize(R.styleable.CircleCompatTextView_cctv_stroke_width, 1);
bgColor = a.getColor(R.styleable.CircleCompatTextView_cctv_background_color, resources.getColor(android.R.color.transparent));
borderColor = a.getColor(R.styleable.CircleCompatTextView_cctv_border_color, resources.getColor(android.R.color.background_dark));
a.recycle();
init();
}
private void init() {
paintCircle.setColor(bgColor);
paintCircle.setFlags(Paint.ANTI_ALIAS_FLAG);
paintStroke.setColor(borderColor);
paintStroke.setStyle(Paint.Style.STROKE);
paintStroke.setStrokeWidth(strokeWidth);
paintStroke.setFlags(Paint.ANTI_ALIAS_FLAG);
}
#Override
public void draw(Canvas canvas) {
canvas.drawCircle(cxCy, cxCy, cxCy - strokeWidth / 2, paintStroke);
canvas.drawCircle(cxCy, cxCy, cxCy - strokeWidth / 2, paintCircle);
super.draw(canvas);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int size = ((height > width) ? height : width);
cxCy = size / 2;
setMeasuredDimension(size, size);
}
}
Step 3: Usage of custom view
<CircleCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center|center_vertical"
android:padding="16dp"
android:textAlignment="center"
app:cctv_background_color="#android:color/transparent"
app:cctv_border_color="#android:color/background_dark"
app:cctv_stroke_width="2dp" />
Here is the output

Adding ripple effect for View in onClick

Hello I am trying to add a ripple effect onClick method for View, but this one no working. All my items having an ID, but I don't know how to call it
Here is a code.
#Override
public void onClick(View v) {
int[] attrs = new int[]{R.attr.selectableItemBackground};
TypedArray typedArray = getActivity().obtainStyledAttributes(attrs);
int backgroundResource = typedArray.getResourceId(0, 0);
v.setBackgroundResource(backgroundResource);
switch (v.getId()) {
case ACTION_PLAY_ID:
Log.d(MainActivity.TAG, getString(R.string.detail_action_play));
v.setBackgroundResource(backgroundResource);
Intent intent = new Intent(getActivity(), PlayerActivity.class);
intent.putExtra(Video.VIDEO_TAG, videoModel);
startActivity(intent);
break;
case ACTION_BOOKMARK_ID:
if (bookmarked) {
v.setBackgroundResource(backgroundResource);
deleteFromBookmarks();
((ImageView) v).setImageDrawable(res.getDrawable(R.drawable.star_outline));
} else {
v.setBackgroundResource(backgroundResource);
addToBookmarks();
((ImageView) v).setImageDrawable(res.getDrawable(R.drawable.star));
}
break;
case ACTION_REMINDER_ID:
if (!isReminderSet) {
createReminderDialog((ImageView) v);
} else {
cancelReminder(liveTvProgram.getProgramId());
((ImageView) v).setImageDrawable(res.getDrawable(R.drawable.alarm));
}
break;
}
}
For Lubomir
i have something like this but not working too:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = inflater.inflate(R.layout.item_detail, container, false);
ButterKnife.bind(this, view);
View myView = view.findViewById(R.id.actions_container);
int[] attrs = new int[]{R.attr.selectableItemBackground};
TypedArray typedArray = getActivity().obtainStyledAttributes(attrs);
int backgroundResource = typedArray.getResourceId(0, 0);
myView.setBackgroundResource(backgroundResource);
loadImage();
init();
return view;
}
ImageViews(actionbuttons) is creating in java for LinearLayout actions_container
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/header_image"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:layout_marginTop="#dimen/detail_image_1_state"
android:elevation="8dp"/>
<RelativeLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="#dimen/detail_bottom_margin"
android:layout_marginTop="#dimen/detail_top_margin"
android:background="#color/primary_color">
<LinearLayout
android:id="#+id/actions_container"
android:layout_width="match_parent"
android:layout_height="#dimen/detail_actions_height"
android:layout_alignParentTop="true"
android:background="#drawable/ripple_effect_image"
android:elevation="2dp"
android:orientation="horizontal"
android:paddingLeft="300dp"
android:paddingStart="300dp"/>
<LinearLayout
android:id="#+id/content_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/actions_container"
android:orientation="vertical"
android:paddingLeft="300dp"
android:paddingStart="300dp">
<TextView
android:id="#+id/title"
style="#style/TextTitleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/subtitle"
style="#style/TextSubtitleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="#+id/duration"
style="#style/TextSubtitleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/season"
style="#style/TextDescriptionStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="#+id/episode"
style="#style/TextDescriptionStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
<TextView
android:id="#+id/description"
style="#style/TextDescriptionStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="7"/>
</LinearLayout>
<FrameLayout
android:id="#+id/recommended_frame"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_alignParentBottom="true">
<android.support.v17.leanback.widget.HorizontalGridView
android:id="#+id/recommendation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingLeft="10dp"
android:paddingRight="10dp"/>
</FrameLayout>
<TextView
android:id="#+id/recommended_text"
style="#style/TextHeaderStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#id/recommended_frame"
android:text="#string/related_programs"/>
</RelativeLayout>
</RelativeLayout>
Also my xml ripple effect file is like:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/dark_primary_color">
<item>
<color android:color="#color/dark_primary_color" />
</item>
<item android:id="#android:id/mask">
<shape android:shape="rectangle">
<solid android:color="?android:colorAccent" />
</shape>
</item>
</ripple>
Clickable Views
In general, ripple effect for regular buttons will work by default in API 21 and for other touchable views, it can be achieved by specifying
android:background="?android:attr/selectableItemBackground"
In code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
View myView = findViewById(R.id.myView);
int[] attrs = new int[]{R.attr.selectableItemBackground};
TypedArray typedArray = getActivity().obtainStyledAttributes(attrs);
int backgroundResource = typedArray.getResourceId(0, 0);
myView.setBackgroundResource(backgroundResource);
}
As stated in Lubomir Babev's answer, adding android:background="?android:attr/selectableItemBackground" does the trick.
However, if your view already has a background, you can use the same on the android:foreground attribute instead:
android:background="#color/anyColor"
android:foreground="?android:attr/selectableItemBackground"
android:foreground is only supported by API 23+ though.
create ripple background
view_background.xml
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#color/blue" >
<item android:drawable="#drawable/view_normal">
</item>
</ripple>
view_noraml.xml //this is how you view appears in normal
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners
android:radius="#dimen/button_corner"/>
<solid
android:color="#android:color/transparent"/>
<stroke
android:width="0.5dp"
android:color="#color/white"/>
</shape>
now set the view_background to your view
example
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
android:foreground="#drawable/view_background"
android:clickable="true"
android:focusable="true"
>
<ImageView
android:id="#+id/grid_item_imageView"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_gravity="center"
android:scaleType="centerInside"
/>
</FrameLayout>
I know this is a pretty old thread but just in case the above answers didn't work, I'd recommend you to try the below code as it worked for me:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content">
The key thing to notice are the clickable and focusable.
The solution for this is simple easy in my side.
Here is ripple effect:
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#BFB3F7">
<item android:id="#android:id/mask">
<shape android:shape="oval">
<solid android:color="#color/button_background_color" />
</shape>
</item>
</ripple>
and next on the class i need to search function
setBackground
Then i need declare a drawable item to it. something like this:
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
v.setBackground(res.getDrawable(R.drawable.ripple_effect_for_buttons));
scrollContainer(false);
} else {
v.setBackground(null);
if (recommendation.getFocusedChild() != null) {
scrollContainer(true);
}
}
}
And YUPII its working
You can add:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
android:background="#drawable/ripple"/>
In Kotlin it could be easily done with an extension functions.
fun TypedArray.use(block: TypedArray.() -> Unit) {
try {
block()
} finally {
this.recycle()
}
}
fun Context.getStyledAttributes(#StyleableRes attrs: IntArray, block: TypedArray.() -> Unit) =
this.obtainStyledAttributes(attrs).use(block)
fun View.setClickableRipple() {
val attrs = intArrayOf(R.attr.selectableItemBackground)
context.getStyledAttributes(attrs) {
val backgroundResource = getResourceId(0, 0)
setBackgroundResource(backgroundResource)
}
}

Changing color of the border of the background of a list item

I was going through this tutorial and had the idea of making it so when you press a button, one of the cards borders changes color.
I looked at this solution, but nothing happens.
Here is what I have done:
I have an xml in drawable for the shape (feed_item.xml):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Bottom 2dp Shadow -->
<item>
<shape android:shape="rectangle">
<solid android:color="#d8d8d8" />
<corners android:radius="7dp" />
</shape>
</item>
<!-- White Top color -->
<item android:bottom="3px" android:id="#+id/feedsquare">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- view background color -->
<solid
android:color="#color/white" >
</solid>
<!-- view border color and width (I WANT TO CHANGE THIS) -->
<stroke
android:width="1dp"
android:color="#color/white" >
</stroke>
<!-- If you want to add some padding -->
<padding
android:left="4dp"
android:top="4dp"
android:right="4dp"
android:bottom="4dp" >
</padding>
</shape>
</item>
</layer-list>
Then I have a layout that is basically how each card/list item looks (list_row.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:background="#drawable/feed_item"
android:id="#+id/card"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:padding="2dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:id="#+id/title"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:text="MMMMMMMMMM"
android:textSize="#dimen/name3"
android:textColor="#color/black" />
<!--android:scaleType="fitXY"-->
<ImageView android:id="#+id/list_image"
android:layout_height="180dp"
android:layout_margin="2dp"
android:layout_weight="0.04"
android:layout_width="match_parent"
android:scaleType="centerInside"
android:adjustViewBounds="true"
android:src="#mipmap/navigation_refresh"/>
<TextView android:id="#+id/description"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_width="wrap_content"
android:text="MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM"
android:textSize="#dimen/description3"
android:textColor="#color/black" />
</LinearLayout>
Now, I have a fragment with a listview. The fragment does exactly what the tutorial does (show 8 cards). I've added a button to the fragment that I want to change a specific cards border color (in the fragments onactivitycreated):
newpost = (Button) getActivity().findViewById(R.id.reply);
newpost.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
LayerDrawable layers = (LayerDrawable) getActivity().getResources().getDrawable(R.drawable.feed_item);
GradientDrawable shape = (GradientDrawable) (layers.findDrawableByLayerId(R.id.feedsquare));
shape.setStroke(1 ,R.color.green);
}
});
Nothing happens when I press the button. Any ideas as to what I can do?
To show selected item (row) in listview :
create a variable in adapter class :
private int selectedPosition = 0;
Create method in side adapter :
public void setSelectedItem(int position) {
this.selectedPosition = position;
notifyDataSetChanged();
}
Add check in getView methode
if (position == selectedPosition)
{
convertView.setBackground(context.getResources().getDrawable(R.drawable.selector_rect_black_trans_bg));
}
else convertView.setBackgroundColor(context.getResources().getColor(android.R.color.transparent));
selector_rect_black_trans_bg.xml :
<solid android:color="#color/gray1" />
<stroke
android:width="2dp"
android:color="#color/gray6" />
<corners
android:bottomLeftRadius="0dp"
android:bottomRightRadius="0dp"
android:topLeftRadius="0dp"
android:topRightRadius="0dp" />
In Activity, only you need to pass position in adapter to show highlighted.
its tested code and it will work.

How to make progress bar fill slowly

I have a progressbar in drawable. I want it to fill slowly whenset progress is done. That is it I should be able to see it filling, not in a flash. Also I have a texview inside that progressbar, I want that textview to keep revolving and as soon as the set progress filling completes, the textview should stop revolving and display progress.
Here is my code:
Layout:
<ProgressBar
android:id="#+id/circularProgressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="150dip"
android:layout_height="150dip"
android:layout_centerInParent="true"
android:indeterminate="false"
android:max="100"
android:progress="0"
android:progressDrawable="#drawable/progressbar" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:textSize="47sp"
android:textStyle="bold"
android:textColor="#color/Theme" />
</RelativeLayout>
progressbar.xml
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/background">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="7.0"
android:useLevel="false" >
<solid android:color="#color/Red" />
</shape>
</item>
<item android:id="#android:id/progress">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="7.0" >
<solid android:color="#color/Theme" />
</shape>
</item>
</layer-list>
Also, I have a textview inside this progressbar, I want it to keep rotating until the progress is done. How to do that, I have an animation for that but it is not working.
Here is the code:
rotate.xml
<rotate xmlns:android="http://schemas.android.com/apk/res/android" >
android:duration="4000"
android:fromdegrees="0"
android:pivotx="50%"
android:pivoty="50%"
android:todegrees="360"
android:toyscale="0.0"
</rotate>
It gives warnings like this: Unexpected text found in layout file: "android:fromdegrees="0" android:pivotx="50%"
android:pivoty="50%" android:todegrees="360" android:to..."
Use this code it will help you.
Required Stuff:
CustomProgressDialog
anim
drawble
layout
1) CustomProgressDialog
package com.est.framework.android.ui;
import android.app.Dialog;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.sc.restclient.R;
// TODO: Auto-generated Javadoc
/**
* The Class CustomProgressDialog.
*/
public class CustomProgressDialog extends Dialog {
/**
* Instantiates a new custom progress dialog.
*
* #param context the context
* #param theme the theme
*/
public CustomProgressDialog(Context context, int theme) {
super(context, theme);
}
/* (non-Javadoc)
* #see android.app.Dialog#onWindowFocusChanged(boolean)
*/
#Override
public void onWindowFocusChanged(boolean hasFocus) {
ImageView imageView = (ImageView) findViewById(R.id.loadingImageView);
AnimationDrawable yourAnimation = (AnimationDrawable) imageView.getBackground();
yourAnimation.start();
}
/**
* Creates the dialog.
*
* #param context the context
* #param title the title
* #param message the message
* #return the custom progress dialog
*/
public static CustomProgressDialog createDialog(Context context,String title) {
CustomProgressDialog dialog = new CustomProgressDialog(context,android.R.style.Theme_Panel);
dialog.setContentView(R.layout.dialogimg);
int width = ViewGroup.LayoutParams.MATCH_PARENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
dialog.getWindow().setLayout(width, height);
TextView mloadMsg = (TextView)dialog.findViewById(R.id.loadMsg);
if (title != null) {
mloadMsg.setText(title);
}else{
mloadMsg.setVisibility(View.GONE);
}
dialog.getWindow().getAttributes().gravity = Gravity.CENTER;
dialog.setCancelable(false);
return dialog;
}
}
2) Layout
<?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:background="#drawable/pop_bg_bitmap"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/loadingImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="#anim/loading_anim" />
<TextView
android:id="#+id/loadMsg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:layout_gravity="center_horizontal"
android:textColor="#color/btn_stroke_text"
android:text="Loading..." />
</LinearLayout>
3) Anim
<?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/progress_1" android:duration="500" />
<item android:drawable="#drawable/progress_2" android:duration="500" />
<item android:drawable="#drawable/progress_3" android:duration="500" />
<item android:drawable="#drawable/progress_4" android:duration="500" />
</animation-list>
4) Drawable
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/fancybox_overlay"
android:antialias="false"
android:dither="true"
android:tileMode="repeat"
>
</bitmap>
Images :
fancybox_overlay.png
progress_1.png
progress_2.png
progress_3.png
progress_4.png
Create a Property for the progress:
final Property<ProgressBar, Integer> progressProperty = new Property<ProgressBar, Integer>(
int.class, "progress") {
#Override
public Integer get(ProgressBar object) {
return object.getProgress();
}
#Override
public void set(ProgressBar object, Integer value) {
object.setProgress(value);
}
};
Create and start an ObjectAnimator for that property on your ProgressBar (mProgressBar):
private void animateProgressBar(int targetProgress) {
ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, progressProperty, targetProgress);
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(300);
anim.start();
}
You can costumize the animation with Interpolators, different duration, ecc
You can also use:
private void animateProgressBar(int targetProgress) {
ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, "progress", targetProgress);
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(300);
anim.start();
}
without declarying the Property, but I don't like this approach that much.
I don't know about the text rotation, but for slowly increasing the progress bar, you can try this one:
mProgressBar is a global progress bar variable which is holding the instance of your progress bar
mProgress is a global integer variable initially set to 0, to monitor the current level of your progress bar.
pSize is the amount you want to increase the progress bar from the current level.
pSleepTime is the speed you want the progress bar to fill up. I usually use 50.
private void setProgressBar(int pSize, int pSleepTime) throws InterruptedException {
for(int i=0;i<pSize && mProgress<100;i++){
mProgress++;
Thread.sleep(pSleepTime);
mProgressBar.setProgress(mProgress);
}
}
You may use Handler and Runnable.
Make the Handler execute postDelayed(yourRunnable, DELAY); in a new method called void next() or something.
In the run() method of yourRunnable, increase the progress position by X amount (very little, like 1 percent or something depending on your desire), and invalidate() your progress bar. After the progress bar increases the progress position by X amount, invoke next() again, which will, execute yourRunnable.run() again, which will increase the progress position by X amount (or you may gradually increase amount using a little more complex math, instead of static X amount), and so goes the cycle until the progress fills up to your desired amount.
private ProgressAnimator animator;
#Override
public void onDraw(Canvas c) {
super.onDraw(c);
if (animator.started) {
animator.next();
}
}
public void animateProgress(float end, IAnimator.PostAnimationAction postPostAnimationAction) {
animator.start(end, postPostAnimationAction);
}
private class ProgressAnimator {
static final long DELAY = 10;
// NOTE:
// "MULTIPLY_FACTOR" IS OPTIONAL.
// I USED THIS TO INCREASE THE PROGRESS SMOOTHLY AT
// DYNAMIC SPEED, NOT AT STATIC SPEED.
// IF YOU WANT STATIC INCREASE OF THE PROGRESS,
// DONT USE THIS.
static final float MULTIPLY_FACTOR = 0.2f;
float endPosition;
float remaining;
boolean started;
PostAnimationAction postAnimationAction;
Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
if (Math.abs(remaining) > 1) {
raiseProgress(/* pass the current progress position here*/);
} else {
end();
}
}
};
/**
* Constructor.
*
*/
ProgressSweepAnimator() {
init();
}
#Override
public void init() {
started = false;
}
// NOTE:
// "PostPostAnimationAction" IS OPTIONAL. I CREATED AND USED THIS
// BECAUSE I WANTED TO DO SOMETHING AFTER THE PROGRESS
// ANIMATION IS FINISHED.
public void start(float endPosition, PostAnimationAction postPostAnimationAction) {
this.endPosition = endPosition;
start(postPostAnimationAction);
}
#Override
public void start(PostAnimationAction postAnimationAction) {
// Initialize status.
started = true;
this.postAnimationAction = postAnimationAction;
// Find out the current progress.
float start = /* get the current progress position here*/;
remaining = end - start;
raiseProgress(start);
}
#Override
public void next() {
handler.postDelayed(runnable, DELAY);
}
private void raiseProgress(float from) {
float toRaise = remaining * MULTIPLY_FACTOR;
remaining -= toRaise;
raiseProgressTo(from + toRaise);
}
#Override
public void end() {
raiseTo(end);
init();
// NOTE:
// THIS IS OPTIONAL BUT MAY BE VERY USEFUL, SO I
// JUST LEFT THIS OUT HERE.
// Notify the subscriber about the completion of the Burst action.
postAnimationAction.onActionComplete();
}
}
Below is the code I am using for gradually filling circular progressbar-
xml
<ProgressBar
android:id="#+id/progress"
android:layout_width="100dp"
android:layout_height="100dp"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="false"
android:layout_centerInParent="true"
android:max="100"
android:visibility="gone"
android:progressDrawable="#drawable/background" />
background.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="#android:id/secondaryProgress">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:useLevel="true"
android:thicknessRatio="14.0">
<gradient
android:startColor="#999999"
android:endColor="#999999"
android:centerColor="#999999"
android:type="sweep" />
</shape>
</item>
<item android:id="#android:id/background">
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:thicknessRatio="14.0"
android:useLevel="false" >
<solid android:color="#color/white" />
</shape>
</item>
<item android:id="#android:id/progress">
<rotate
android:fromDegrees="270"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270" >
<shape
android:innerRadiusRatio="3"
android:shape="ring"
android:useLevel="true"
android:thicknessRatio="14.0">
<rotate
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%" />
<gradient
android:startColor="#8E58D4"
android:endColor="#8E58D4"
android:centerColor="#8E58D4"
android:type="sweep" />
</shape>
</rotate>
</item>
</layer-list>
Code
mProgressBar = (ProgressBar) activity.findViewById(R.id.progress);
Resources res = getResources();
Drawable drawable = res.getDrawable(R.drawable.background);
mProgressBar.setProgressDrawable(drawable);
ObjectAnimator animation = ObjectAnimator.ofInt(mProgressBar, "progress", 0, 100);
animation.setDuration(10000);

ValueAnimator to change background color

I want to create a screen with a backgroundcolor that keeps changing from red to blue. For some reason it always crashes when i try to instantiate the ValueAnimator. I have no idea what's wrong with my code
Thank you
Animation class
public BackgroundAnimation(Context context){
super(context);
ValueAnimator colorAnim = ObjectAnimator.ofInt(R.anim.animator, "backgroundColor", Color.RED, Color.BLUE);
colorAnim.setDuration(3000);
colorAnim.setEvaluator(new ArgbEvaluator());
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
}
animator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="backgroundColor"/>
</set>
Main class
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.menu);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
container.addView(new BackgroundAnimation(this));
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:id="#+id/TextView01"
android:gravity="center"
android:textSize="20sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/TextView02"
android:gravity="center"
android:textSize="20sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<ImageView
android:id="#+id/ImageView01"
android:layout_width="fill_parent"
android:layout_height="300sp"/>
</LinearLayout>
You can use the ObjectAnimator to change the background color:
For API >= 21 :
ObjectAnimator colorAnimator = ObjectAnimator.ofArgb(travelersListView.getBackground().mutate(), "tint", mCurrentBackground, mFadeColor);
colorAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
colorAnimator.start();
For backward support from API 16 use this:
ObjectAnimator colorAnimator = ObjectAnimator.ofObject(travelersListView.getBackground().mutate(), "tint", new ArgbEvaluator(), mCurrentBackground, mFadeColor);
colorAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
colorAnimator.start();
There is not id parameter in XML file for LinearLayout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="#+id/container">
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.menu);
LinearLayout container = (LinearLayout) findViewById(R.id.container);
changeBackground(container, "#F44336", "#2196F3"); //#F44336 : Red , #2196F3 : Blue
}
public void changeBackground(final View view, String color1, String color2) {
ValueAnimator anim = new ValueAnimator();
anim.setIntValues(Color.parseColor(color1), Color.parseColor(color2));
anim.setEvaluator(new ArgbEvaluator());
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
view.setBackgroundColor((Integer) valueAnimator.getAnimatedValue());
}
});
anim.setDuration(2000);
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.start();
}
Try this, Hope this helps
No variant of ObjectAnimator.ofInt() takes resource ID as parameter. Please read this for declaring animations in XML. http://developer.android.com/guide/topics/graphics/prop-animation.html#declaring-xml

Categories

Resources