androidandroid-layoutandroid-animationandroid-graphics

how to make star shape and animate it in android?


I want to make a star shape for my project. and I searched so, now I can make finally star shape by using canvas.

but next what I want is really really difficult to me. It`s so nightmare. I tried and searched but nothing works for me.

what I want is star have to consist of lines with no background color. only line.. across the line..

And then one line is expressed and fade, the next line is created and fade again, then the line is created and then fade again, and I want it to be permanent this action. Until I leave this activity's screen to another.


Solution

  • This code is taken from a project I was working on some time back. I think it does what you need.

    First of all, I have no idea about how you have created the lines for the star. I just used vector drawables to create the star lines (for more details about how to work with VectorDrawables have a look at this post). I should warn you that I made it in a hurry so it's not going to be pretty

    Warning: This post is going to be long

    star1.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">    
        <path android:pathData="M20,24L12,0"
            android:strokeColor="@color/starColor"
            android:strokeWidth="0.1"/>    
    </vector>
    

    star2.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">    
        <path android:pathData="M4,24L12,0"
            android:strokeColor="@color/starColor"
            android:strokeWidth="0.1"/>    
    </vector>
    

    star3.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">    
        <path android:pathData="M0,8L24,8"
            android:strokeColor="@color/starColor"
            android:strokeWidth="0.1"/>    
    </vector>
    

    star4.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
        <path android:pathData="M4,24L24,8"
            android:strokeColor="@color/starColor"
            android:strokeWidth="0.1"/>
    </vector>
    

    star5.xml

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
        <path android:pathData="M20,24L0,8"
            android:strokeColor="@color/starColor"
            android:strokeWidth="0.1"/>
    </vector>
    

    Ok. Now that you have all the required drawables, let's jump to the Activity XML and create the layout. Just the basic stuff here. I'll be using 5 ImageViews to hold the different star lines (which makes it convenient to animate but could cause performance issues which we'll talk about later on). I'll be using a ConstraintLayout as the root view.

    activity_test.xml

    <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">
    
        <ImageView
            android:id="@+id/image1"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:alpha="0"/>
    
        <ImageView
            android:id="@+id/image2"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:alpha="0"/>
    
        <ImageView
            android:id="@+id/image3"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:alpha="0"/>
    
        <ImageView
            android:id="@+id/image4"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:alpha="0"/>
    
        <ImageView
            android:id="@+id/image5"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            android:alpha="0"/>
    
    </android.support.constraint.ConstraintLayout>
    

    As you might have noticed I have not assigned any of the drawables to the ImageView using the android:src property. I'd encourage you to go ahead and try doing that. Meanwhile I am adding the images programmatically.

    Above the onCreate method declare the following variables

    private ImageView image1, image2, image3, image4, image5;
    private Context context;
    private int i = 1;
    private long duration = 800;
    private Handler animHandler;
    

    animHandler is going to be responsible to keep the animation running. I'll be using i to keep track of which ImageView to animate. And as the name suggests, the field duration is going to hold the required duration for the animation.

    Here is the rest of the code. I'll be providing comments wherever possible.

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
    
        // Initialising the imageview. I'm using SDK 26 so I did not
        // require typecasting.
        image1 = findViewById(R.id.image1);
        image2 = findViewById(R.id.image2);
        image3 = findViewById(R.id.image3);
        image4 = findViewById(R.id.image4);
        image5 = findViewById(R.id.image5);
    
        context = TestActivity.this;
    
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                setupView(); // This method will initialize all IVs 
                             // and add the vector drawable as bitmap
                animHandler = new Handler();
                startAnim();
            }
        }, 200);
    
    }
    

    setupView

    private void setupView() {
        setVectorDrawable(image1, ContextCompat.getDrawable(context,R.drawable.star1));
        setVectorDrawable(image2, ContextCompat.getDrawable(context,R.drawable.star2));
        setVectorDrawable(image3, ContextCompat.getDrawable(context,R.drawable.star3));
        setVectorDrawable(image4, ContextCompat.getDrawable(context,R.drawable.star4));
        setVectorDrawable(image5, ContextCompat.getDrawable(context,R.drawable.star5));
    }
    

    setVectorDrawable

    private void setVectorDrawable(ImageView imageView, Drawable drawable) {
        Bitmap bitmap = Bitmap.createBitmap(imageView.getWidth(),
                imageView.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
    
        imageView.setImageBitmap(bitmap);
    }
    

    Over here, I'm creating 5 different bitmaps to hold the 5 lines. This won't be too much of an issue just yet. But for bigger projects (I had to use 69 bitmaps together) having a lot of bitmaps in the memory is probably not a good practice. 5 bitmaps should work just fine.

    startAnim

    private void startAnim() {
        runnable.run();
    }
    

    runnable

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            switch (i) {
                case 1:
                    animateStarIn(image1);
                    break;
                case 2:
                    animateStarIn(image2);
                    break;
    
                case 3:
                    animateStarIn(image3);
                    break;
                case 4:
                    animateStarIn(image4);
                    break;
    
                case 5:
                    animateStarIn(image5);
                    break;
                case 6:
                    animateStartOut(image1);
                    break;
    
                case 7:
                    animateStartOut(image2);
                    break;
                case 8:
                    animateStartOut(image3);
                    break;
    
                case 9:
                    animateStartOut(image4);
                    break;
                case 10:
                    animateStartOut(image5);
                    break;
            }
            i++;
            if (i == 11) i = 1;
            animHandler.postDelayed(runnable, duration);
        }
    };
    
    private void animateStarIn(ImageView imageView) {
        imageView.animate().alpha(1).setDuration(duration).setInterpolator(new AccelerateInterpolator());
    }
    private void animateStartOut (ImageView imageView) {
        imageView.animate().alpha(0).setDuration(duration).setInterpolator(new DecelerateInterpolator());
    }
    

    To be brief, I am creating a runnable that will animate the different ImageViews differently depending on the value variable i holds.

    Let me stress again that I have posted this code from a project that I worked on some time back. Even if it does not meet your requirement directly I'd encourage you to experiment and play around with it for a bit to get it working.

    Edit

    This animation works by ensuring the runnable repeats. To stop the animation use

    animHandler.removeCallbacks(runnable);