implement a spinning activity indicator similar to iOS in Android

后端 未结 4 785
慢半拍i
慢半拍i 2021-02-02 02:58

I am trying to implement the spinning activity similar to the the one I have placed below in Android. I believe I should use the ProgressDialog. My issue arises from how to actu

4条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-02 03:46

    I wrote my own custom LoadingIndicatorView.

    It consists of two files:

    • LoadingIndicatorBarView
    • LoadingIndicatorView

    Pros:

    • Programmatically created, no PNG antics meaning scalable and crisp :D
    • Customizable bar colors and corner radius (if you understand my code)

    Cons:

    • Not as performant as the iOS version (I'm just a beginner Android developer coming from iOS background, what do you expect?) :P

    Disclaimer:

    • Don't blame me if your project blows up, I'm putting this as free public domain code.

    You'll notice my coding style and structure resemble my iOS programming codes a lot. I do everything programmatically, no XML if I can get away with it.

    How to use this Loading Indicator

    After you've copied and pasted all three class source codes into their Java file, you want to use the LoadingIndicatorView class, you shouldn't need to touch the other class, unless you want to customise the colour or rounded corner of each bar.

    Create an instance of LoadingIndicatorView like this in your Activity:

    import com.companyName.myApplication.views.LoadingIndicatorView;
    
    public class MyActivity extends AppCompatActivity
    {
        public mainLayout RelativeLayout;
        ...
        public LoadingIndicatorView loadingIndicator;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
    
            initViews();
            initLayouts();
            addViews();
        }
    
        public void initViews()
        {
            mainLayout = new RelativeLayout(this);
            mainLayout.setBackgroundColor(Color.BLACK);
    
            ...
    
            // ---------------------------------------------------
            // 40 here is the radius of the circle
            // try and use multiples of 2, e.g. 40, 60, 80 etc
            // ---------------------------------------------------
            loadingIndicator = new LoadingIndicatorView(this, 40);
    
            // hide until ready to start animating
            loadingIndicator.setAlpha(0.0f);
        }
    
        public void initLayouts()
        {
            ...
    
            // Need API level 17 for this, set in your AndroidManifeset.xml
            mainLayout.setId(View.generateViewId());
            loadingIndicator.setId(View.generateViewId());
    
            RelativeLayout.LayoutParams loadingIndicatorLayoutParams = new RelativeLayout.LayoutParams(
                    (int)(loadingIndicator.radius * 2.0f),
                    (int)(loadingIndicator.radius * 2.0f)
            );
    
            loadingIndicatorLayoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
    
            loadingIndicator.setLayoutParams(loadingIndicatorLayoutParams);
        }
    
        public void addViews()
        {
            ...
    
            mainLayout.addView(loadingIndicator);
    
            setContentView(mainLayout);
        }
    }
    

    Once you're ready to show it, e.g. in a button click listener, then you call:

    loadingIndicator.startAnimating();
    

    When you want to stop and hide the indicator, call:

    loadingIndicator.stopAnimating();
    

    You end up with something like this:

    LoadingIndicatorView.java

    package com.companyName.myApplication.views;
    
    import android.app.Activity;
    import android.content.Context;
    import android.graphics.Color;
    import android.graphics.ColorFilter;
    import android.graphics.PorterDuff;
    import android.os.CountDownTimer;
    import android.os.Handler;
    import android.os.Looper;
    import android.util.Log;
    import android.view.View;
    import android.view.animation.RotateAnimation;
    import android.widget.RelativeLayout;
    
    import java.lang.reflect.Array;
    import java.util.ArrayList;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /**
     * Created by Zhang on 11/02/16.
     */
    public class LoadingIndicatorView extends RelativeLayout
    {
        private Context context;
    
        private int numberOfBars;
    
        public ArrayList arrBars;
    
        public float radius;
    
        private boolean isAnimating;
        private int currentFrame;
    
        private final Handler handler = new Handler();
        private Runnable playFrameRunnable;
    
        public LoadingIndicatorView(Context context, float radius)
        {
            super(context);
    
            this.context = context;
            this.radius = radius;
            this.numberOfBars = 12;
    
            initViews();
            initLayouts();
            addViews();
            spreadBars();
        }
    
        public void initViews()
        {
            arrBars = new ArrayList();
    
            for(int i = 0; i < numberOfBars; i++)
            {
                LoadingIndicatorBarView bar = new LoadingIndicatorBarView(context, radius / 10.0f);
    
                arrBars.add(bar);
            }
        }
    
        public void initLayouts()
        {
            for(int i = 0; i < numberOfBars; i++)
            {
                LoadingIndicatorBarView bar = arrBars.get(i);
    
                bar.setId(View.generateViewId());
    
                RelativeLayout.LayoutParams barLayoutParams = new RelativeLayout.LayoutParams(
                        (int)(radius / 5.0f),
                        (int)(radius / 2.0f)
                );
    
                barLayoutParams.addRule(ALIGN_PARENT_TOP);
                barLayoutParams.addRule(CENTER_HORIZONTAL);
    
                bar.setLayoutParams(barLayoutParams);
            }
        }
    
        public void addViews()
        {
            for(int i = 0; i < numberOfBars; i++)
            {
                LoadingIndicatorBarView bar = arrBars.get(i);
    
                addView(bar);
            }
        }
    
        public void spreadBars()
        {
            int degrees = 0;
    
            for(int i = 0; i < arrBars.size(); i++)
            {
                LoadingIndicatorBarView bar = arrBars.get(i);
    
                rotateBar(bar, degrees);
    
                degrees += 30;
            }
        }
    
        private void rotateBar(LoadingIndicatorBarView bar, float degrees)
        {
            RotateAnimation animation = new RotateAnimation(0, degrees, radius / 10.0f, radius);
            animation.setDuration(0);
            animation.setFillAfter(true);
    
            bar.setAnimation(animation);
            animation.start();
        }
    
        public void startAnimating()
        {
            setAlpha(1.0f);
    
            isAnimating = true;
    
            playFrameRunnable = new Runnable()
            {
                @Override
                public void run()
                {
                    playFrame();
                }
            };
    
            // recursive function until isAnimating is false
            playFrame();
        }
    
        public void stopAnimating()
        {
            isAnimating = false;
    
            setAlpha(0.0f);
    
            invalidate();
    
            playFrameRunnable = null;
        }
    
        private void playFrame()
        {
            if(isAnimating)
            {
                resetAllBarAlpha();
                updateFrame();
    
                handler.postDelayed(playFrameRunnable, 0);
            }
        }
    
        private void updateFrame()
        {
            if (isAnimating)
            {
                showFrame(currentFrame);
                currentFrame += 1;
    
                if (currentFrame > 11)
                {
                    currentFrame = 0;
                }
            }
        }
    
        private void resetAllBarAlpha()
        {
            LoadingIndicatorBarView bar = null;
    
            for (int i = 0; i < arrBars.size(); i++)
            {
                bar = arrBars.get(i);
    
                bar.setAlpha(0.5f);
            }
        }
    
        private void showFrame(int frameNumber)
        {
            int[] indexes = getFrameIndexesForFrameNumber(frameNumber);
    
            gradientColorBarSets(indexes);
        }
    
        private int[] getFrameIndexesForFrameNumber(int frameNumber)
        {
            if(frameNumber == 0)
            {
                return indexesFromNumbers(0, 11, 10, 9);
            }
            else if(frameNumber == 1)
            {
                return indexesFromNumbers(1, 0, 11, 10);
            }
            else if(frameNumber == 2)
            {
                return indexesFromNumbers(2, 1, 0, 11);
            }
            else if(frameNumber == 3)
            {
                return indexesFromNumbers(3, 2, 1, 0);
            }
            else if(frameNumber == 4)
            {
                return indexesFromNumbers(4, 3, 2, 1);
            }
            else if(frameNumber == 5)
            {
                return indexesFromNumbers(5, 4, 3, 2);
            }
            else if(frameNumber == 6)
            {
                return indexesFromNumbers(6, 5, 4, 3);
            }
            else if(frameNumber == 7)
            {
                return indexesFromNumbers(7, 6, 5, 4);
            }
            else if(frameNumber == 8)
            {
                return indexesFromNumbers(8, 7, 6, 5);
            }
            else if(frameNumber == 9)
            {
                return indexesFromNumbers(9, 8, 7, 6);
            }
            else if(frameNumber == 10)
            {
                return indexesFromNumbers(10, 9, 8, 7);
            }
            else
            {
                return indexesFromNumbers(11, 10, 9, 8);
            }
        }
    
        private int[] indexesFromNumbers(int i1, int i2, int i3, int i4)
        {
            int[] indexes = {i1, i2, i3, i4};
            return indexes;
        }
    
        private void gradientColorBarSets(int[] indexes)
        {
            float alpha = 1.0f;
    
            LoadingIndicatorBarView barView = null;
    
            for(int i = 0; i < indexes.length; i++)
            {
                int barIndex = indexes[i];
    
                barView = arrBars.get(barIndex);
    
    
                barView.setAlpha(alpha);
                alpha -= 0.125f;
            }
    
            invalidate();
        }
    }
    

    LoadingIndicatorBarView.java

    package com.companyName.myApplication.views;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.widget.RelativeLayout;
    
    import com.companyName.myApplication.helper_classes.ToolBox;
    
    /**
     * Created by Zhang on 11/02/16.
     */
    public class LoadingIndicatorBarView extends RelativeLayout
    {
        private Context context;
        private float cornerRadius;
    
        public LoadingIndicatorBarView(Context context, float cornerRadius)
        {
            super(context);
    
            this.context = context;
            this.cornerRadius = cornerRadius;
    
            initViews();
        }
    
        public void initViews()
        {
            setBackground(ToolBox.roundedCornerRectWithColor(
                    Color.argb(255, 255, 255, 255), cornerRadius));
    
            setAlpha(0.5f);
        }
    
        public void resetColor()
        {
            setBackground(ToolBox.roundedCornerRectWithColor(
                    Color.argb(255, 255, 255, 255), cornerRadius));
    
            setAlpha(0.5f);
        }
    }
    

    Toolbox.java

    package com.companyName.myApplication.helper_classes;
    
    import android.content.Context;
    import android.content.res.Configuration;
    import android.content.res.Resources;
    import android.graphics.Paint;
    import android.graphics.drawable.ShapeDrawable;
    import android.graphics.drawable.shapes.RoundRectShape;
    
    /**
     * Created by Zhang on 3/02/16.
     */
    public class ToolBox
    {
        private static ToolBox instance;
        public Context context;
    
        private ToolBox()
        {
    
        }
    
        public synchronized static ToolBox getInstance()
        {
            if(instance == null)
            {
                instance = new ToolBox();
            }
    
            return instance;
        }
    
        public static ShapeDrawable roundedCornerRectOutlineWithColor(int color, float cornerRadius,
                                                                      float strokeWidth)
        {
            float[] radii = new float[] {
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius
            };
    
            RoundRectShape roundedCornerShape = new RoundRectShape(radii, null, null);
    
            ShapeDrawable shape = new ShapeDrawable();
            shape.getPaint().setColor(color);
            shape.setShape(roundedCornerShape);
            shape.getPaint().setStrokeWidth(strokeWidth);
            shape.getPaint().setStyle(Paint.Style.STROKE);
    
            return shape;
        }
    
        public static ShapeDrawable roundedCornerRectWithColor(int color, float cornerRadius)
        {
            float[] radii = new float[] {
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius,
                    cornerRadius, cornerRadius
            };
    
            RoundRectShape roundedCornerShape = new RoundRectShape(radii, null, null);
    
            ShapeDrawable shape = new ShapeDrawable();
            shape.getPaint().setColor(color);
            shape.setShape(roundedCornerShape);
    
            return shape;
        }
    
        public static ShapeDrawable roundedCornerRectWithColor(int color, float topLeftRadius, float
                topRightRadius, float bottomRightRadius, float bottomLeftRadius)
        {
            float[] radii = new float[] {
                    topLeftRadius, topLeftRadius,
                    topRightRadius, topRightRadius,
                    bottomRightRadius, bottomRightRadius,
                    bottomLeftRadius, bottomLeftRadius
            };
    
            RoundRectShape roundedCornerShape = new RoundRectShape(radii, null, null);
    
            ShapeDrawable shape = new ShapeDrawable();
            shape.getPaint().setColor(color);
            shape.setShape(roundedCornerShape);
    
            return shape;
        }
    
        public static int getScreenWidth()
        {
            return Resources.getSystem().getDisplayMetrics().widthPixels;
        }
    
        public static int getScreenHeight()
        {
            return Resources.getSystem().getDisplayMetrics().heightPixels;
        }
    
        public static int getScreenOrientation(Context context)
        {
            return context.getResources().getConfiguration().orientation;
        }
    
        public static boolean isLandscapeOrientation(Context context)
        {
            return getScreenOrientation(context) == Configuration.ORIENTATION_LANDSCAPE;
        }
    
    }
    

    This Toolbox class is my convenience helper class to create rounded corner shapes etc in all my projects.

    Hope that helps :D

提交回复
热议问题