ソースを参照

add loading to improve error reporting when repeatedly pressing select+start

wangyongj 1 年間 前
コミット
664fcfad21
21 ファイル変更1431 行追加21 行削除
  1. 49 0
      app/src/main/java/com/xugame/gameconsole/dialog/LoadingDialog.java
  2. 46 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/AnimationUtils.java
  3. 24 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/CircleSprite.java
  4. 12 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Ease.java
  5. 22 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/FloatProperty.java
  6. 23 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/IntProperty.java
  7. 52 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/KeyFrameInterpolator.java
  8. 18 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/RectSprite.java
  9. 62 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/ShapeSprite.java
  10. 27 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpinKitStyle.java
  11. 117 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpinKitView.java
  12. 446 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Sprite.java
  13. 208 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteAnimatorBuilder.java
  14. 102 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteContainer.java
  15. 20 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteFactory.java
  16. 56 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/ThreeBounce.java
  17. 53 0
      app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Wave.java
  18. 40 21
      app/src/main/java/com/xugame/gameconsole/emulator/RetroArchEmulatorActivity.java
  19. 19 0
      app/src/main/res/layout/dialog_loadging.xml
  20. 25 0
      app/src/main/res/values/attrs.xml
  21. 10 0
      app/src/main/res/values/themes.xml

+ 49 - 0
app/src/main/java/com/xugame/gameconsole/dialog/LoadingDialog.java

@@ -0,0 +1,49 @@
+package com.xugame.gameconsole.dialog;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import com.xugame.gameconsole.R;
+import com.xugame.gameconsole.dialog.loadingview.SpinKitView;
+import com.xugame.gameconsole.util.Util;
+
+public class LoadingDialog extends BaseDialog {
+    private static final String TAG = "LoadingDialogTAG";
+    private Context mContext;
+    private SpinKitView mSpinKitView;
+
+    protected LoadingDialog(Context context, int themeResId) {
+        super(context, themeResId);
+        mContext=context;
+        this.init();
+    }
+
+    public LoadingDialog(Context context) {
+        super(context,R.style.DialogNoPadding);
+        mContext=context;
+        this.init();
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        int w = Util.getSize(1920);
+        int h = Util.getSize(1080);
+        getWindow().setLayout(w, h);
+        super.onCreate(savedInstanceState);
+
+    }
+
+    private void init() {
+        View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_loadging, null);
+        mSpinKitView = view.findViewById(R.id.spin_kit_view);
+        setContentView(view);
+    }
+
+    @Override
+    public void dismiss() {
+        super.dismiss();
+    }
+}

+ 46 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/AnimationUtils.java

@@ -0,0 +1,46 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+
+public class AnimationUtils {
+    public static void start(Animator animator) {
+        if (animator != null && !animator.isStarted()) {
+            animator.start();
+        }
+    }
+
+    public static void stop(Animator animator) {
+        if (animator != null && !animator.isRunning()) {
+            animator.end();
+        }
+    }
+
+    public static void start(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            sprite.start();
+        }
+    }
+
+    public static void stop(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            sprite.stop();
+        }
+    }
+
+    public static boolean isRunning(Sprite... sprites) {
+        for (Sprite sprite : sprites) {
+            if (sprite.isRunning()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean isRunning(ValueAnimator animator) {
+        return animator != null && animator.isRunning();
+    }
+
+    public static boolean isStarted(ValueAnimator animator) {
+        return animator != null && animator.isStarted();
+    }
+}

+ 24 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/CircleSprite.java

@@ -0,0 +1,24 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+public class CircleSprite extends ShapeSprite {
+
+    //画圆形
+    @Override
+    public ValueAnimator onCreateAnimation() {
+        return null;
+    }
+
+    @Override
+    public void drawShape(Canvas canvas, Paint paint) {
+        if (getDrawBounds() != null) {
+            int radius = Math.min(getDrawBounds().width(), getDrawBounds().height()) / 2;
+            canvas.drawCircle(getDrawBounds().centerX(),
+                    getDrawBounds().centerY(),
+                    radius, paint);
+        }
+    }
+}

+ 12 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Ease.java

@@ -0,0 +1,12 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+
+import android.view.animation.Interpolator;
+
+import androidx.core.view.animation.PathInterpolatorCompat;
+
+public class Ease {
+    public static Interpolator inOut() {
+        return PathInterpolatorCompat.create(0.42f, 0f, 0.58f, 1f);
+    }
+}

+ 22 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/FloatProperty.java

@@ -0,0 +1,22 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.util.Property;
+
+public abstract class  FloatProperty<T> extends Property<T, Float> {
+
+    public FloatProperty(String name) {
+        super(Float.class, name);
+    }
+
+    /**
+     * A type-specific override of the {@link #set(Object, Float)} that is faster when dealing
+     * with fields of type <code>float</code>.
+     */
+    public abstract void setValue(T object, float value);
+
+    @Override
+    final public void set(T object, Float value) {
+        setValue(object, value);
+    }
+
+}

+ 23 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/IntProperty.java

@@ -0,0 +1,23 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.util.Property;
+
+
+public abstract class IntProperty<T> extends Property<T, Integer> {
+
+    public IntProperty(String name) {
+        super(Integer.class, name);
+    }
+
+    /**
+     * A type-specific override of the {@link #set(Object, Integer)} that is faster when dealing
+     * with fields of type <code>int</code>.
+     */
+    public abstract void setValue(T object, int value);
+
+    @Override
+    final public void set(T object, Integer value) {
+        setValue(object, value);
+    }
+
+}

+ 52 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/KeyFrameInterpolator.java

@@ -0,0 +1,52 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.animation.TimeInterpolator;
+import android.view.animation.Interpolator;
+
+import androidx.core.view.animation.PathInterpolatorCompat;
+
+public class KeyFrameInterpolator implements Interpolator {
+
+    private TimeInterpolator interpolator;
+    private float[] fractions;
+
+
+    public static KeyFrameInterpolator easeInOut(float... fractions) {
+        KeyFrameInterpolator interpolator = new KeyFrameInterpolator(Ease.inOut());
+        interpolator.setFractions(fractions);
+        return interpolator;
+    }
+
+    public static KeyFrameInterpolator pathInterpolator(float controlX1, float controlY1,
+                                                        float controlX2, float controlY2,
+                                                        float... fractions) {
+        KeyFrameInterpolator interpolator = new KeyFrameInterpolator(PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2));
+        interpolator.setFractions(fractions);
+        return interpolator;
+    }
+
+    public KeyFrameInterpolator(TimeInterpolator interpolator, float... fractions) {
+        this.interpolator = interpolator;
+        this.fractions = fractions;
+    }
+
+    public void setFractions(float... fractions) {
+        this.fractions = fractions;
+    }
+
+    @Override
+    public float getInterpolation(float input) {
+        if (fractions.length > 1) {
+            for (int i = 0; i < fractions.length - 1; i++) {
+                float start = fractions[i];
+                float end = fractions[i + 1];
+                float duration = end - start;
+                if (input >= start && input <= end) {
+                    input = (input - start) / duration;
+                    return start + (interpolator.getInterpolation(input)
+                            * duration);
+                }
+            }
+        }
+        return interpolator.getInterpolation(input);
+    }
+}

+ 18 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/RectSprite.java

@@ -0,0 +1,18 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+public class RectSprite extends ShapeSprite {
+    @Override
+    public ValueAnimator onCreateAnimation() {
+        return null;
+    }
+
+    @Override
+    public void drawShape(Canvas canvas, Paint paint) {
+        if (getDrawBounds() != null) {
+            canvas.drawRect(getDrawBounds(), paint);
+        }
+    }
+}

+ 62 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/ShapeSprite.java

@@ -0,0 +1,62 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+
+public abstract class ShapeSprite  extends Sprite {
+
+    private Paint mPaint;
+    private int mUseColor;
+    private int mBaseColor;
+
+    public ShapeSprite() {
+        setColor(Color.WHITE);
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(mUseColor);
+    }
+
+    @Override
+    public void setColor(int color) {
+        mBaseColor = color;
+        updateUseColor();
+    }
+
+    @Override
+    public int getColor() {
+        return mBaseColor;
+    }
+
+    @SuppressWarnings("unused")
+    public int getUseColor() {
+        return mUseColor;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        super.setAlpha(alpha);
+        updateUseColor();
+    }
+
+    private void updateUseColor() {
+        int alpha = getAlpha();
+        alpha += alpha >> 7;
+        final int baseAlpha = mBaseColor >>> 24;
+        final int useAlpha = baseAlpha * alpha >> 8;
+        mUseColor = (mBaseColor << 8 >>> 8) | (useAlpha << 24);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    protected final void drawSelf(Canvas canvas) {
+        mPaint.setColor(mUseColor);
+        drawShape(canvas, mPaint);
+    }
+
+    public abstract void drawShape(Canvas canvas, Paint paint);
+}

+ 27 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpinKitStyle.java

@@ -0,0 +1,27 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+public enum SpinKitStyle {
+//    loading 动画种类
+    ROTATING_PLANE(0),
+    DOUBLE_BOUNCE(1),
+    WAVE(2),//线性
+    WANDERING_CUBES(3),
+    PULSE(4),
+    CHASING_DOTS(5),
+    THREE_BOUNCE(6),
+    CIRCLE(7),
+    CUBE_GRID(8),
+    FADING_CIRCLE(9),
+    FOLDING_CUBE(10),
+    ROTATING_CIRCLE(11),
+    MULTIPLE_PULSE(12),
+    PULSE_RING(13),
+    MULTIPLE_PULSE_RING(14);
+
+    @SuppressWarnings({"FieldCanBeLocal", "unused"})
+    private int value;
+
+    SpinKitStyle(int value) {
+        this.value = value;
+    }
+}

+ 117 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpinKitView.java

@@ -0,0 +1,117 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ProgressBar;
+
+import com.xugame.gameconsole.R;
+
+public class SpinKitView extends ProgressBar {
+
+    private SpinKitStyle mStyle;
+    private int mColor;
+    private Sprite mSprite;
+
+    public SpinKitView(Context context) {
+        this(context, null);
+    }
+
+    public SpinKitView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.SpinKitViewStyle);
+    }
+
+    public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, R.style.SpinKitView);
+    }
+
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    public SpinKitView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpinKitView, defStyleAttr,
+                defStyleRes);
+        mStyle = SpinKitStyle.values()[a.getInt(R.styleable.SpinKitView_SpinKit_Style, 6)];
+        mColor = a.getColor(R.styleable.SpinKitView_SpinKit_Color, Color.WHITE);
+        a.recycle();
+        init();
+        setIndeterminate(true);
+    }
+
+    private void init() {
+        Sprite sprite = SpriteFactory.create(mStyle);
+        sprite.setColor(mColor);
+        setIndeterminateDrawable(sprite);
+    }
+
+    @Override
+    public void setIndeterminateDrawable(Drawable d) {
+        if (!(d instanceof Sprite)) {
+            throw new IllegalArgumentException("this d must be instanceof Sprite");
+        }
+        setIndeterminateDrawable((Sprite) d);
+    }
+
+    public void setIndeterminateDrawable(Sprite d) {
+        super.setIndeterminateDrawable(d);
+        mSprite = d;
+        if (mSprite.getColor() == 0) {
+
+            mSprite.setColor(mColor);
+        }
+        onSizeChanged(getWidth(), getHeight(), getWidth(), getHeight());
+        if (getVisibility() == VISIBLE) {
+
+            mSprite.start();
+        }
+    }
+
+    @Override
+    public Sprite getIndeterminateDrawable() {
+        return mSprite;
+    }
+
+    public void setColor(int color) {
+        this.mColor = color;
+        if (mSprite != null) {
+
+            mSprite.setColor(color);
+        }
+        invalidate();
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who) {
+        super.unscheduleDrawable(who);
+        if (who instanceof Sprite) {
+
+            ((Sprite) who).stop();
+        }
+    }
+
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        super.onWindowFocusChanged(hasWindowFocus);
+        if (hasWindowFocus) {
+            if (mSprite != null && getVisibility() == VISIBLE) {
+
+                mSprite.start();
+            }
+        }
+    }
+
+    @Override
+    public void onScreenStateChanged(int screenState) {
+        super.onScreenStateChanged(screenState);
+        if (screenState == View.SCREEN_STATE_OFF) {
+
+            if (mSprite != null) {
+
+                mSprite.stop();
+            }
+        }
+    }
+}

+ 446 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Sprite.java

@@ -0,0 +1,446 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.animation.ValueAnimator;
+import android.graphics.Camera;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.util.Property;
+
+public abstract class Sprite extends Drawable implements
+        ValueAnimator.AnimatorUpdateListener
+        , Animatable
+        , Drawable.Callback {
+
+    private float scale = 1;
+    private float scaleX = 1;
+    private float scaleY = 1;
+    private float pivotX;
+    private float pivotY;
+    private int animationDelay;
+    private int rotateX;
+    private int rotateY;
+    private int translateX;
+    private int translateY;
+    private int rotate;
+    private float translateXPercentage;
+    private float translateYPercentage;
+    private ValueAnimator animator;
+    private int alpha = 255;
+    private static final Rect ZERO_BOUNDS_RECT = new Rect();
+    protected Rect drawBounds = ZERO_BOUNDS_RECT;
+    private Camera mCamera;
+    private Matrix mMatrix;
+
+    public Sprite() {
+        mCamera = new Camera();
+        mMatrix = new Matrix();
+    }
+
+    public abstract int getColor();
+
+    public abstract void setColor(int color);
+
+    @Override
+    public void setAlpha(int alpha) {
+        this.alpha = alpha;
+    }
+
+    @Override
+    public int getAlpha() {
+        return alpha;
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    public float getTranslateXPercentage() {
+        return translateXPercentage;
+    }
+
+    public void setTranslateXPercentage(float translateXPercentage) {
+        this.translateXPercentage = translateXPercentage;
+    }
+
+    public float getTranslateYPercentage() {
+        return translateYPercentage;
+    }
+
+    public void setTranslateYPercentage(float translateYPercentage) {
+        this.translateYPercentage = translateYPercentage;
+    }
+
+    public int getTranslateX() {
+        return translateX;
+    }
+
+    public void setTranslateX(int translateX) {
+        this.translateX = translateX;
+    }
+
+    public int getTranslateY() {
+        return translateY;
+    }
+
+    public void setTranslateY(int translateY) {
+        this.translateY = translateY;
+    }
+
+    public int getRotate() {
+        return rotate;
+    }
+
+    public void setRotate(int rotate) {
+        this.rotate = rotate;
+    }
+
+    public float getScale() {
+        return scale;
+    }
+
+    public void setScale(float scale) {
+        this.scale = scale;
+        setScaleX(scale);
+        setScaleY(scale);
+    }
+
+    public float getScaleX() {
+        return scaleX;
+    }
+
+    public void setScaleX(float scaleX) {
+        this.scaleX = scaleX;
+    }
+
+    public float getScaleY() {
+        return scaleY;
+    }
+
+    public void setScaleY(float scaleY) {
+        this.scaleY = scaleY;
+    }
+
+    public int getRotateX() {
+        return rotateX;
+    }
+
+    public void setRotateX(int rotateX) {
+        this.rotateX = rotateX;
+    }
+
+    public int getRotateY() {
+        return rotateY;
+    }
+
+    public void setRotateY(int rotateY) {
+        this.rotateY = rotateY;
+    }
+
+    public float getPivotX() {
+        return pivotX;
+    }
+
+    public void setPivotX(float pivotX) {
+        this.pivotX = pivotX;
+    }
+
+    public float getPivotY() {
+        return pivotY;
+    }
+
+    public void setPivotY(float pivotY) {
+        this.pivotY = pivotY;
+    }
+
+    @SuppressWarnings("unused")
+    public int getAnimationDelay() {
+        return animationDelay;
+    }
+
+    public Sprite setAnimationDelay(int animationDelay) {
+        this.animationDelay = animationDelay;
+        return this;
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+
+    }
+
+    public abstract ValueAnimator onCreateAnimation();
+
+    @Override
+    public void start() {
+        if (AnimationUtils.isStarted(animator)) {
+            return;
+        }
+
+        animator = obtainAnimation();
+        if (animator == null) {
+            return;
+        }
+
+     AnimationUtils.start(animator);
+        invalidateSelf();
+    }
+
+    public ValueAnimator obtainAnimation() {
+        if (animator == null) {
+            animator = onCreateAnimation();
+        }
+        if (animator != null) {
+            animator.addUpdateListener(this);
+            animator.setStartDelay(animationDelay);
+        }
+        return animator;
+    }
+
+    @Override
+    public void stop() {
+        if (AnimationUtils.isStarted(animator)) {
+            animator.removeAllUpdateListeners();
+            animator.end();
+            reset();
+        }
+    }
+
+    protected abstract void drawSelf(Canvas canvas);
+
+    public void reset() {
+        scale = 1;
+        rotateX = 0;
+        rotateY = 0;
+        translateX = 0;
+        translateY = 0;
+        rotate = 0;
+        translateXPercentage = 0f;
+        translateYPercentage = 0f;
+    }
+
+    @Override
+    public boolean isRunning() {
+        return AnimationUtils.isRunning(animator);
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        setDrawBounds(bounds);
+    }
+
+    public void setDrawBounds(Rect drawBounds) {
+        setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom);
+    }
+
+    public void setDrawBounds(int left, int top, int right, int bottom) {
+        this.drawBounds = new Rect(left, top, right, bottom);
+        setPivotX(getDrawBounds().centerX());
+        setPivotY(getDrawBounds().centerY());
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable who) {
+        invalidateSelf();
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+
+    }
+
+    @Override
+    public void onAnimationUpdate(ValueAnimator animation) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.invalidateDrawable(this);
+        }
+    }
+
+    public Rect getDrawBounds() {
+        return drawBounds;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        int tx = getTranslateX();
+        tx = tx == 0 ? (int) (getBounds().width() * getTranslateXPercentage()) : tx;
+        int ty = getTranslateY();
+        ty = ty == 0 ? (int) (getBounds().height() * getTranslateYPercentage()) : ty;
+        canvas.translate(tx, ty);
+        canvas.scale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
+        canvas.rotate(getRotate(), getPivotX(), getPivotY());
+
+        if (getRotateX() != 0 || getRotateY() != 0) {
+            mCamera.save();
+            mCamera.rotateX(getRotateX());
+            mCamera.rotateY(getRotateY());
+            mCamera.getMatrix(mMatrix);
+            mMatrix.preTranslate(-getPivotX(), -getPivotY());
+            mMatrix.postTranslate(getPivotX(), getPivotY());
+            mCamera.restore();
+            canvas.concat(mMatrix);
+        }
+        drawSelf(canvas);
+    }
+
+    public Rect clipSquare(Rect rect) {
+        int w = rect.width();
+        int h = rect.height();
+        int min = Math.min(w, h);
+        int cx = rect.centerX();
+        int cy = rect.centerY();
+        int r = min / 2;
+        return new Rect(
+                cx - r,
+                cy - r,
+                cx + r,
+                cy + r
+        );
+    }
+
+    public static final Property<Sprite, Integer> ROTATE_X = new IntProperty<Sprite>("rotateX") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotateX(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotateX();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ROTATE = new IntProperty<Sprite>("rotate") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotate(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotate();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ROTATE_Y = new IntProperty<Sprite>("rotateY") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setRotateY(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getRotateY();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Integer> TRANSLATE_X = new IntProperty<Sprite>("translateX") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setTranslateX(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getTranslateX();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Integer> TRANSLATE_Y = new IntProperty<Sprite>("translateY") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setTranslateY(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getTranslateY();
+        }
+    };
+
+    public static final Property<Sprite, Float> TRANSLATE_X_PERCENTAGE = new FloatProperty<Sprite>("translateXPercentage") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setTranslateXPercentage(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getTranslateXPercentage();
+        }
+    };
+
+    public static final Property<Sprite, Float> TRANSLATE_Y_PERCENTAGE = new FloatProperty<Sprite>("translateYPercentage") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setTranslateYPercentage(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getTranslateYPercentage();
+        }
+    };
+
+    @SuppressWarnings("unused")
+    public static final Property<Sprite, Float> SCALE_X = new FloatProperty<Sprite>("scaleX") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScaleX(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScaleX();
+        }
+    };
+
+    public static final Property<Sprite, Float> SCALE_Y = new FloatProperty<Sprite>("scaleY") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScaleY(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScaleY();
+        }
+    };
+
+    public static final Property<Sprite, Float> SCALE = new FloatProperty<Sprite>("scale") {
+        @Override
+        public void setValue(Sprite object, float value) {
+            object.setScale(value);
+        }
+
+        @Override
+        public Float get(Sprite object) {
+            return object.getScale();
+        }
+    };
+
+    public static final Property<Sprite, Integer> ALPHA = new IntProperty<Sprite>("alpha") {
+        @Override
+        public void setValue(Sprite object, int value) {
+            object.setAlpha(value);
+        }
+
+        @Override
+        public Integer get(Sprite object) {
+            return object.getAlpha();
+        }
+    };
+
+}

+ 208 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteAnimatorBuilder.java

@@ -0,0 +1,208 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.animation.Keyframe;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.util.Log;
+import android.util.Property;
+import android.view.animation.Animation;
+import android.view.animation.Interpolator;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class SpriteAnimatorBuilder {
+
+    private static final String TAG = "SpriteAnimatorBuilder";
+    private Sprite sprite;
+    private Interpolator interpolator;
+    private int repeatCount = Animation.INFINITE;
+    private long duration = 2000;
+    private int startFrame = 0;
+    private Map<String, FrameData> fds = new HashMap<>();
+
+
+    class FrameData<T> {
+        public FrameData(float[] fractions, Property property, T[] values) {
+            this.fractions = fractions;
+            this.property = property;
+            this.values = values;
+        }
+
+        float[] fractions;
+        Property property;
+        T[] values;
+    }
+
+    class IntFrameData extends FrameData<Integer> {
+
+        public IntFrameData(float[] fractions, Property property, Integer[] values) {
+            super(fractions, property, values);
+        }
+    }
+
+    class FloatFrameData extends FrameData<Float> {
+
+        public FloatFrameData(float[] fractions, Property property, Float[] values) {
+            super(fractions, property, values);
+        }
+    }
+
+    public SpriteAnimatorBuilder(Sprite sprite) {
+        this.sprite = sprite;
+    }
+
+    public SpriteAnimatorBuilder scale(float fractions[], Float... scale) {
+        holder(fractions, Sprite.SCALE, scale);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder alpha(float fractions[], Integer... alpha) {
+        holder(fractions, Sprite.ALPHA, alpha);
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder scaleX(float fractions[], Float... scaleX) {
+        holder(fractions, Sprite.SCALE, scaleX);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder scaleY(float fractions[], Float... scaleY) {
+        holder(fractions, Sprite.SCALE_Y, scaleY);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder rotateX(float fractions[], Integer... rotateX) {
+        holder(fractions, Sprite.ROTATE_X, rotateX);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder rotateY(float fractions[], Integer... rotateY) {
+        holder(fractions, Sprite.ROTATE_Y, rotateY);
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder translateX(float fractions[], Integer... translateX) {
+        holder(fractions, Sprite.TRANSLATE_X, translateX);
+        return this;
+    }
+
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder translateY(float fractions[], Integer... translateY) {
+        holder(fractions, Sprite.TRANSLATE_Y, translateY);
+        return this;
+    }
+
+
+    public SpriteAnimatorBuilder rotate(float fractions[], Integer... rotate) {
+        holder(fractions, Sprite.ROTATE, rotate);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder translateXPercentage(float fractions[], Float... translateXPercentage) {
+        holder(fractions, Sprite.TRANSLATE_X_PERCENTAGE, translateXPercentage);
+        return this;
+    }
+
+    public SpriteAnimatorBuilder translateYPercentage(float[] fractions, Float... translateYPercentage) {
+        holder(fractions, Sprite.TRANSLATE_Y_PERCENTAGE, translateYPercentage);
+        return this;
+    }
+
+    private void holder(float[] fractions, Property property, Float[] values) {
+        ensurePair(fractions.length, values.length);
+        fds.put(property.getName(), new FloatFrameData(fractions, property, values));
+    }
+
+
+    private void holder(float[] fractions, Property property, Integer[] values) {
+        ensurePair(fractions.length, values.length);
+        fds.put(property.getName(), new IntFrameData(fractions, property, values));
+    }
+
+    private void ensurePair(int fractionsLength, int valuesLength) {
+        if (fractionsLength != valuesLength) {
+            throw new IllegalStateException(String.format(
+                    Locale.getDefault(),
+                    "The fractions.length must equal values.length, " +
+                            "fraction.length[%d], values.length[%d]",
+                    fractionsLength,
+                    valuesLength));
+        }
+    }
+
+
+    public SpriteAnimatorBuilder interpolator(Interpolator interpolator) {
+        this.interpolator = interpolator;
+        return this;
+    }
+
+    public SpriteAnimatorBuilder easeInOut(float... fractions) {
+        interpolator(KeyFrameInterpolator.easeInOut(
+                fractions
+        ));
+        return this;
+    }
+
+
+    public SpriteAnimatorBuilder duration(long duration) {
+        this.duration = duration;
+        return this;
+    }
+
+    @SuppressWarnings("unused")
+    public SpriteAnimatorBuilder repeatCount(int repeatCount) {
+        this.repeatCount = repeatCount;
+        return this;
+    }
+
+    public SpriteAnimatorBuilder startFrame(int startFrame) {
+        if (startFrame < 0) {
+            Log.w(TAG, "startFrame should always be non-negative");
+            startFrame = 0;
+        }
+        this.startFrame = startFrame;
+        return this;
+    }
+
+    public ObjectAnimator build() {
+
+        PropertyValuesHolder[] holders = new PropertyValuesHolder[fds.size()];
+        int i = 0;
+        for (Map.Entry<String, FrameData> fd : fds.entrySet()) {
+            FrameData data = fd.getValue();
+            Keyframe[] keyframes = new Keyframe[data.fractions.length];
+            float[] fractions = data.fractions;
+            float startF = fractions[startFrame];
+            for (int j = startFrame; j < (startFrame + data.values.length); j++) {
+                int key = j - startFrame;
+                int vk = j % data.values.length;
+                float fraction = fractions[vk] - startF;
+                if (fraction < 0) {
+                    fraction = fractions[fractions.length - 1] + fraction;
+                }
+                if (data instanceof IntFrameData) {
+                    keyframes[key] = Keyframe.ofInt(fraction, (Integer) data.values[vk]);
+                } else if (data instanceof FloatFrameData) {
+                    keyframes[key] = Keyframe.ofFloat(fraction, (Float) data.values[vk]);
+                } else {
+                    keyframes[key] = Keyframe.ofObject(fraction, data.values[vk]);
+                }
+            }
+            holders[i] = PropertyValuesHolder.ofKeyframe(data.property, keyframes);
+            i++;
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(sprite,
+                holders);
+        animator.setDuration(duration);
+        animator.setRepeatCount(repeatCount);
+        animator.setInterpolator(interpolator);
+        return animator;
+    }
+
+}

+ 102 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteContainer.java

@@ -0,0 +1,102 @@
+package com.xugame.gameconsole.dialog.loadingview;
+import android.animation.ValueAnimator;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+
+public abstract class SpriteContainer  extends Sprite {
+
+    private Sprite[] sprites;
+
+    private int color;
+
+    public SpriteContainer() {
+        sprites = onCreateChild();
+        initCallBack();
+        onChildCreated(sprites);
+    }
+
+    private void initCallBack() {
+        if (sprites != null) {
+            for (Sprite sprite : sprites) {
+                sprite.setCallback(this);
+            }
+        }
+    }
+
+    public void onChildCreated(Sprite... sprites) {
+
+    }
+
+    public int getChildCount() {
+        return sprites == null ? 0 : sprites.length;
+    }
+
+    public Sprite getChildAt(int index) {
+        return sprites == null ? null : sprites[index];
+    }
+
+    @Override
+    public void setColor(int color) {
+        this.color = color;
+        for (int i = 0; i < getChildCount(); i++) {
+            getChildAt(i).setColor(color);
+        }
+    }
+
+    @Override
+    public int getColor() {
+        return color;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        drawChild(canvas);
+    }
+
+    public void drawChild(Canvas canvas) {
+        if (sprites != null) {
+            for (Sprite sprite : sprites) {
+                int count = canvas.save();
+                sprite.draw(canvas);
+                canvas.restoreToCount(count);
+            }
+        }
+    }
+
+    @Override
+    protected void drawSelf(Canvas canvas) {
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        for (Sprite sprite : sprites) {
+            sprite.setBounds(bounds);
+        }
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        AnimationUtils.start(sprites);
+    }
+
+    @Override
+    public void stop() {
+        super.stop();
+        AnimationUtils.stop(sprites);
+    }
+
+    @Override
+    public boolean isRunning() {
+        return AnimationUtils.isRunning(sprites) || super.isRunning();
+    }
+
+    public abstract Sprite[] onCreateChild();
+
+    @Override
+    public ValueAnimator onCreateAnimation() {
+        return null;
+    }
+}

+ 20 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/SpriteFactory.java

@@ -0,0 +1,20 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+public class SpriteFactory {
+    public static Sprite create(SpinKitStyle style) {
+        Sprite sprite = null;
+        switch (style) {//暂时实现方块和小圆点
+
+            case WAVE:
+                sprite = new Wave();
+                break;
+
+            case THREE_BOUNCE:
+                sprite = new ThreeBounce();
+
+            default:
+                break;
+        }
+        return sprite;
+    }
+}

+ 56 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/ThreeBounce.java

@@ -0,0 +1,56 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+
+public class ThreeBounce extends SpriteContainer {
+
+    @Override
+    public Sprite[] onCreateChild() {
+        return new Sprite[]{
+                new Bounce(),
+                new Bounce(),
+                new Bounce()
+        };
+    }
+
+    @Override
+    public void onChildCreated(Sprite... sprites) {
+        super.onChildCreated(sprites);
+        sprites[1].setAnimationDelay(160);
+        sprites[2].setAnimationDelay(320);
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        bounds = clipSquare(bounds);
+        int radius = bounds.width() / 8;
+        int top = bounds.centerY() - radius;
+        int bottom = bounds.centerY() + radius;
+
+        for (int i = 0; i < getChildCount(); i++) {
+            int left = bounds.width() * i / 3
+                    + bounds.left;
+            getChildAt(i).setDrawBounds(
+                    left, top, left + radius * 2, bottom
+            );
+        }
+    }
+
+    private class Bounce extends CircleSprite {
+
+        Bounce() {
+            setScale(0f);
+        }
+
+        @Override
+        public ValueAnimator onCreateAnimation() {
+            float fractions[] = new float[]{0f, 0.4f, 0.8f, 1f};
+            return new SpriteAnimatorBuilder(this).scale(fractions, 0f, 1f, 0f, 0f).
+                    duration(1400).
+                    easeInOut(fractions)
+                    .build();
+        }
+    }
+}

+ 53 - 0
app/src/main/java/com/xugame/gameconsole/dialog/loadingview/Wave.java

@@ -0,0 +1,53 @@
+package com.xugame.gameconsole.dialog.loadingview;
+
+import android.animation.ValueAnimator;
+import android.graphics.Rect;
+import android.os.Build;
+
+public class Wave  extends SpriteContainer {
+
+    @Override
+    public Sprite[] onCreateChild() {
+        WaveItem[] waveItems = new WaveItem[5];
+        for (int i = 0; i < waveItems.length; i++) {
+            waveItems[i] = new WaveItem();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                waveItems[i].setAnimationDelay(600 + i * 100);
+            } else {
+                waveItems[i].setAnimationDelay(-1200 + i * 100);
+            }
+
+        }
+        return waveItems;
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        bounds = clipSquare(bounds);
+        int rw = bounds.width() / getChildCount();
+        int width = bounds.width() / 5 * 3 / 5;
+        for (int i = 0; i < getChildCount(); i++) {
+            Sprite sprite = getChildAt(i);
+            int l = bounds.left + i * rw + rw / 5;
+            int r = l + width;
+            sprite.setDrawBounds(l, bounds.top, r, bounds.bottom);
+        }
+    }
+
+    private class WaveItem extends RectSprite {
+
+        WaveItem() {
+            setScaleY(0.4f);
+        }
+
+        @Override
+        public ValueAnimator onCreateAnimation() {
+            float fractions[] = new float[]{0f, 0.2f, 0.4f, 1f};
+            return new SpriteAnimatorBuilder(this).scaleY(fractions, 0.4f, 1f, 0.4f, 0.4f).
+                    duration(2200).
+                    easeInOut(fractions)
+                    .build();
+        }
+    }
+}

+ 40 - 21
app/src/main/java/com/xugame/gameconsole/emulator/RetroArchEmulatorActivity.java

@@ -16,6 +16,7 @@ import com.xugame.app.AppSystem;
 import com.xugame.app.EnvironmentCallback;
 import com.xugame.bean.InputCode;
 import com.xugame.bean.InputDescriptorBean;
+import com.xugame.gameconsole.dialog.LoadingDialog;
 import com.xugame.gameconsole.dialog.gamemenu.GameMenuDialog;
 import com.xugame.gameconsole.dialog.gamemenu.GameMenuDialogListener;
 import com.xugame.gameconsole.preferences.ConfigFile;
@@ -41,7 +42,8 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
     private boolean quitfocus = false;
 
     private AppSystem system = null;
-    private boolean isBusy=false;
+    private boolean isBusy = false;
+    private LoadingDialog mLoadingDialog;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -122,26 +124,38 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
 //                showDialog();
 //            }
 //        });
-        if(!isBusy){
-            isBusy=true;
-            Intent intent = new Intent();//调出主菜单UI
-            ComponentName componentName = new ComponentName("com.xugame.gameconsoleMenu",
-                    "com.xugame.gameconsole.dialog.localgamesetting.LocalGameSettingDialog");
-            intent.setComponent(componentName);
-            startActivityForResult(intent, 200);
-            DebugUtil.i(TAG, "showLocalExitDialog");
-        }
+
+        runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (!isBusy) {
+                    isBusy = true;
+                    if (mLoadingDialog == null)
+                        mLoadingDialog = new LoadingDialog(RetroArchEmulatorActivity.this);
+                    if (mLoadingDialog.isShowing())
+                        return;
+                    else
+                        mLoadingDialog.show();
+                    Intent intent = new Intent();//调出主菜单UI
+                    ComponentName componentName = new ComponentName("com.xugame.gameconsoleMenu",
+                            "com.xugame.gameconsole.dialog.localgamesetting.LocalGameSettingDialog");
+                    intent.setComponent(componentName);
+                    startActivityForResult(intent, 200);
+                    DebugUtil.i(TAG, "showLocalExitDialog");
+                }
+            }
+        });
+
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        isBusy=false;
-        DebugUtil.i(TAG,"onPause");
+        isBusy = false;
+        DebugUtil.i(TAG, "onPause");
     }
 
 
-
     @Override
     public void onResume() {
         super.onResume();
@@ -242,7 +256,7 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
     @Override
     public void onStop() {
         super.onStop();
-        DebugUtil.i(TAG,"onStop");
+        DebugUtil.i(TAG, "onStop");
         // If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost
         if (quitfocus) System.exit(0);
     }
@@ -251,13 +265,13 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
     public boolean dispatchKeyEvent(KeyEvent event) {
         DebugUtil.i(TAG, "" + event.getKeyCode());
         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                ) {
+        ) {
 //            showDialog();
-            Intent intent=new Intent();//调出主菜单UI
-            ComponentName componentName=new ComponentName("com.xugame.gameconsoleMenu",
+            Intent intent = new Intent();//调出主菜单UI
+            ComponentName componentName = new ComponentName("com.xugame.gameconsoleMenu",
                     "com.xugame.gameconsole.dialog.localgamesetting.LocalGameSettingDialog");
-           intent.setComponent(componentName);
-            startActivityForResult(intent,200);
+            intent.setComponent(componentName);
+            startActivityForResult(intent, 200);
 //            setScan();
             return super.dispatchKeyEvent(event);
         }
@@ -271,7 +285,7 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
         tempIndex++;
         if (tempIndex >= 4)
             tempIndex = 0;
-        DebugUtil.i(TAG,"tempIndex="+tempIndex);
+        DebugUtil.i(TAG, "tempIndex=" + tempIndex);
         if (tempIndex == 0)
             switchFilter(null);
         if (tempIndex == 1)
@@ -303,7 +317,12 @@ public class RetroArchEmulatorActivity extends RetroActivityCamera {
                     break;
             }
         }
-        DebugUtil.i(TAG,"onWindowFocusChanged"+hasFocus);
+        if (!hasFocus) {
+            if (mLoadingDialog != null) {
+                mLoadingDialog.dismiss();
+            }
+        }
+        DebugUtil.i(TAG, "onWindowFocusChanged" + hasFocus);
         super.onWindowFocusChanged(hasFocus);
     }
 

+ 19 - 0
app/src/main/res/layout/dialog_loadging.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:background="#64000000"
+    android:layout_height="match_parent">
+
+    <com.xugame.gameconsole.dialog.loadingview.SpinKitView
+        android:id="@+id/spin_kit_view"
+        style="@style/SpinKitView"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusableInTouchMode="true"
+        android:focusable="true"
+        android:layout_centerInParent="true"
+        android:background="?selectableItemBackgroundBorderless"
+        android:padding="10dp">
+
+    </com.xugame.gameconsole.dialog.loadingview.SpinKitView>
+</RelativeLayout>

+ 25 - 0
app/src/main/res/values/attrs.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+<!--    for loading view-->
+    <attr name="SpinKitViewStyle" format="reference" />
+    <declare-styleable name="SpinKitView">
+        <attr name="SpinKit_Style">
+            <enum name="RotatingPlane" value="0" />
+            <enum name="DoubleBounce" value="1" />
+            <enum name="Wave" value="2" />
+            <enum name="WanderingCubes" value="3" />
+            <enum name="Pulse" value="4" />
+            <enum name="ChasingDots" value="5" />
+            <enum name="ThreeBounce" value="6" />
+            <enum name="Circle" value="7" />
+            <enum name="CubeGrid" value="8" />
+            <enum name="FadingCircle" value="9" />
+            <enum name="FoldingCube" value="10" />
+            <enum name="RotatingCircle" value="11" />
+            <enum name="MultiplePulse" value="12" />
+            <enum name="PulseRing" value="13" />
+            <enum name="MultiplePulseRing" value="14" />
+        </attr>
+        <attr name="SpinKit_Color" format="color" />
+    </declare-styleable>
+</resources>

+ 10 - 0
app/src/main/res/values/themes.xml

@@ -14,4 +14,14 @@
         <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
         <!-- Customize your theme here. -->
     </style>
+
+
+<!--    for loading view-->
+    <style name="SpinKitView">
+        <item name="android:indeterminateOnly">true</item>
+        <item name="android:minWidth">48dip</item>
+        <item name="android:maxWidth">48dip</item>
+        <item name="android:minHeight">48dip</item>
+        <item name="android:maxHeight">48dip</item>
+    </style>
 </resources>