Shape Loading View Android Image Source unsplash.com.

Here is the GitHub link for this project shape-loading-android.

Introduction

Everybody will agree that an app will get incredible interest from users when it has a great design. If you disagree try publishing an app that has an awful UI and see what happens. The huge majority of apps in the Play Store use the normal progress bar or spinner to show progress. Nonetheless, some high-quality apps innovate with nice animations to show the user that he should wait. Let’s see how to make a different loading animation using different shapes and colours.

In this article, we will create a shape loading view to indicate the progress of a task in android. The shape loading view will be inside activity and also within a dialogue box depending on the user’s preference. We will use Java programming language for the development of this android project.

This project will offer insights into the working of shape loading view in android. It will help the reader to get a better understanding of the inner-machinery that goes behind implementing such features.

Photo Preview

Glossary

Progress Bar Android ProgressBar is a visual watch that shows some progress. The Android Progress bar shows a bar representing completion. It is helpful because it gives the user an idea of ​​when to complete their task. Using ProgressBar is a good practice for the user experience as it reflects the progress of the given task (such as downloading a photo) to the user.

Steps:

Step 1: Adding required dependencies

Firstly, go to the app-level build.gradle file and add the following dependency:

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
compile project(':shapeloading')
}
view raw build.gradle hosted with ❤ by GitHub

Secondly, the build.gradle file will be as shown below:

apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion '25.0.0'
defaultConfig {
minSdkVersion 9
targetSdkVersion 30
versionCode 1
versionName "1.0.3"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.nineoldandroids:library:2.4.0'
}
view raw build.gradle hosted with ❤ by GitHub

Step 2: Creating the activity_main.xml file

Now, come to your activity_main.xml file which is responsible for designing the layout of the app and it’s located in the layout folder under the res folder. Change your default to Linear Layout then add additional attributes like this:

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:text="View"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/button2"
android:text="Dialog"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
view raw activity_main.xml hosted with ❤ by GitHub

As shown above, the activity_main.xml is connected to two layouts which are activity_view_demo.xml and activity_dialog_demo.xml. Go to the layout folder in the res folder and create a new layout called activity_view_demo.xml and add the following code as shown below.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
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.dennism.ViewDemoActivity">
<com.dennism.widget.LoadingView
android:id="@+id/loadView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:loadingText="Loading..." />
</RelativeLayout>

Create another layout called activity_dialog_demo.xml and add the following code as shown below.

<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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="com.dennism.DialogDemoActivity">
<Button
android:id="@+id/button1"
android:text="show"
android:layout_centerInParent="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</RelativeLayout>

Step 3: Creating the LoadingView.java file

The startLoading function will be the first to implement with the help of the constructor LoadingView. Then usedObject animator in the upThrow function to enable the different shapes to get the bouncing effect as shown below. Create another object called mFreeFallRunnable which is responsible for rotating the different shapes using the x and y-axis. Use the setVisibity function to display and hide the progress bar when necessary. Finally, the freeFall function uses the AnimatorSet object to give the progress bar the downfall effect.

package com.dennism.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.dennism.shapeloading.R;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;
public class LoadingView extends LinearLayout {
private static final int ANIMATION_DURATION = 500;
private static final float FACTOR = 1.2f;
private static float mDistance = 200;
private ShapeLoadingView mShapeLoadingView;
private ImageView mIndicationIm;
private TextView mLoadTextView;
private int mTextAppearance;
private String mLoadText;
private AnimatorSet mUpAnimatorSet;
private AnimatorSet mDownAnimatorSet;
private boolean mStopped = false;
private int mDelay;
public LoadingView(Context context) {
super(context);
init(context, null);
}
public LoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
setOrientation(VERTICAL);
mDistance = dip2px(context, 54f);
LayoutInflater.from(context).inflate(R.layout.load_view, this, true);
mShapeLoadingView = (ShapeLoadingView) findViewById(R.id.shapeLoadingView);
mIndicationIm = (ImageView) findViewById(R.id.indication);
mLoadTextView = (TextView) findViewById(R.id.promptTV);
ViewHelper.setScaleX(mIndicationIm, 0.2f);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);
String loadText = typedArray.getString(R.styleable.LoadingView_loadingText);
int textAppearance = typedArray.getResourceId(R.styleable.LoadingView_loadingText, -1);
mDelay = typedArray.getInteger(R.styleable.LoadingView_delay, 80);
typedArray.recycle();
if (textAppearance != -1) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mLoadTextView.setTextAppearance(textAppearance);
} else {
mLoadTextView.setTextAppearance(getContext(), textAppearance);
}
}
setLoadingText(loadText);
}
private int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getVisibility() == VISIBLE) {
startLoading(mDelay);
}
}
private Runnable mFreeFallRunnable = new Runnable() {
@Override
public void run() {
ViewHelper.setRotation(mShapeLoadingView, 180f);
ViewHelper.setTranslationY(mShapeLoadingView, 0f);
ViewHelper.setScaleX(mIndicationIm, 0.2f);
mStopped = false;
freeFall();
}
};
private void startLoading(long delay) {
if (mDownAnimatorSet != null && mDownAnimatorSet.isRunning()) {
return;
}
this.removeCallbacks(mFreeFallRunnable);
if (delay > 0) {
this.postDelayed(mFreeFallRunnable, delay);
} else {
this.post(mFreeFallRunnable);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopLoading();
}
private void stopLoading() {
mStopped = true;
if (mUpAnimatorSet != null) {
if (mUpAnimatorSet.isRunning()) {
mUpAnimatorSet.cancel();
}
mUpAnimatorSet.removeAllListeners();
for (Animator animator : mUpAnimatorSet.getChildAnimations()) {
animator.removeAllListeners();
}
mUpAnimatorSet = null;
}
if (mDownAnimatorSet != null) {
if (mDownAnimatorSet.isRunning()) {
mDownAnimatorSet.cancel();
}
mDownAnimatorSet.removeAllListeners();
for (Animator animator : mDownAnimatorSet.getChildAnimations()) {
animator.removeAllListeners();
}
mDownAnimatorSet = null;
}
this.removeCallbacks(mFreeFallRunnable);
}
@Override
public void setVisibility(int visibility) {
this.setVisibility(visibility, mDelay);
}
public void setVisibility(int visibility, int delay) {
super.setVisibility(visibility);
if (visibility == View.VISIBLE) {
startLoading(delay);
} else {
stopLoading();
}
}
public void setDelay(int delay) {
mDelay = delay;
}
public int getDelay() {
return mDelay;
}
public void setLoadingText(CharSequence loadingText) {
if (TextUtils.isEmpty(loadingText)) {
mLoadTextView.setVisibility(GONE);
} else {
mLoadTextView.setVisibility(VISIBLE);
}
mLoadTextView.setText(loadingText);
}
public CharSequence getLoadingText(){
return mLoadTextView.getText();
}
public void upThrow() {
if (mUpAnimatorSet == null) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mShapeLoadingView, "translationY", mDistance, 0);
ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(mIndicationIm, "scaleX", 1f, 0.2f);
ObjectAnimator objectAnimator1 = null;
switch (mShapeLoadingView.getShape()) {
case SHAPE_RECT:
objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, "rotation", 0, 180);
break;
case SHAPE_CIRCLE:
objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, "rotation", 0, 180);
break;
case SHAPE_TRIANGLE:
objectAnimator1 = ObjectAnimator.ofFloat(mShapeLoadingView, "rotation", 0, 180);
break;
}
mUpAnimatorSet = new AnimatorSet();
mUpAnimatorSet.playTogether(objectAnimator, objectAnimator1, scaleIndication);
mUpAnimatorSet.setDuration(ANIMATION_DURATION);
mUpAnimatorSet.setInterpolator(new DecelerateInterpolator(FACTOR));
mUpAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mStopped) {
freeFall();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
mUpAnimatorSet.start();
}
/**
* whereabouts
*/
public void freeFall() {
if (mDownAnimatorSet == null) {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mShapeLoadingView, "translationY", 0, mDistance);
ObjectAnimator scaleIndication = ObjectAnimator.ofFloat(mIndicationIm, "scaleX", 0.2f, 1f);
mDownAnimatorSet = new AnimatorSet();
mDownAnimatorSet.playTogether(objectAnimator, scaleIndication);
mDownAnimatorSet.setDuration(ANIMATION_DURATION);
mDownAnimatorSet.setInterpolator(new AccelerateInterpolator(FACTOR));
mDownAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (!mStopped) {
mShapeLoadingView.changeShape();
upThrow();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
mDownAnimatorSet.start();
}
}
view raw LoadingView.java hosted with ❤ by GitHub

Step 4: Creating the ShapeLoadingDialog.java file

You will use the shapeLoadingDialog constructor to make the Dialog box work effectively as shown below.

package com.dennism.widget;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import com.dennism.shapeloading.R;
public class ShapeLoadingDialog extends Dialog{
private LoadingView mLoadingView;
private Builder mBuilder;
private ShapeLoadingDialog(Builder builder) {
super(builder.mContext, R.style.custom_dialog);
mBuilder = builder;
setCancelable(mBuilder.mCancelable);
setCanceledOnTouchOutside(mBuilder.mCanceledOnTouchOutside);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_dialog);
mLoadingView = (LoadingView) findViewById(R.id.loadView);
mLoadingView.setDelay(mBuilder.mDelay);
mLoadingView.setLoadingText(mBuilder.mLoadText);
setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
mLoadingView.setVisibility(View.GONE);
}
});
}
@Override
public void show() {
super.show();
mLoadingView.setVisibility(View.VISIBLE);
}
public Builder getBuilder() {
return mBuilder;
}
public static class Builder{
private Context mContext;
private int mDelay = 80;
private CharSequence mLoadText;
private boolean mCancelable = true;
private boolean mCanceledOnTouchOutside = true;
public Builder(Context context) {
mContext = context;
}
public Builder delay(int delay) {
mDelay = delay;
return this;
}
public Builder loadText(CharSequence loadText) {
mLoadText = loadText;
return this;
}
public Builder loadText(int resId) {
mLoadText = mContext.getString(resId);
return this;
}
public Builder cancelable(boolean cancelable) {
mCancelable = cancelable;
mCanceledOnTouchOutside = cancelable;
return this;
}
public Builder canceledOnTouchOutside(boolean canceledOnTouchOutside) {
mCanceledOnTouchOutside = canceledOnTouchOutside;
return this;
}
public ShapeLoadingDialog build(){
return new ShapeLoadingDialog(this);
}
public ShapeLoadingDialog show(){
ShapeLoadingDialog dialog = build();
dialog.show();
return dialog;
}
}
}

Step 5: Creating the ShapeLoadingView.java file

This activity will only be able to work by linking it to the few activities above and by using the several functions in place. It is also where we are changing the different shapes, circle, triangle by using the changeShape function. Lastly, the duration of how each shape changes to the next shape is dependent on the magic number.

package com.dennism.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import com.dennism.shapeloading.R;
import com.nineoldandroids.animation.ArgbEvaluator;
public class ShapeLoadingView extends View {
/**
* Draw a circle with the Sebel curve
*/
private static final float mMagicNumber = 0.55228475f;
private static final float genhao3 = 1.7320508075689f;
private static final float mTriangle2Circle =0.25555555f;
private Shape mShape = Shape.SHAPE_CIRCLE;
private ArgbEvaluator mArgbEvaluator=new ArgbEvaluator();
private int mTriangleColor ;
private int mCircleColor ;
private int mRectColor ;
public ShapeLoadingView(Context context) {
super(context);
init(context);
}
public ShapeLoadingView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ShapeLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ShapeLoadingView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
mTriangleColor = getColor(context, R.color.triangle);
mCircleColor =getColor(context, R.color.circle);
mRectColor = getColor(context, R.color.rect);
mPaint = new Paint();
mPaint.setColor(mTriangleColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
public boolean mIsLoading = false;
private Paint mPaint;
private float mControlX = 0;
private float mControlY = 0;
private float mAnimPercent;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(getVisibility()==GONE){
return;
}
// FIXME: 15/6/15 Animation to be optimized
switch (mShape) {
case SHAPE_TRIANGLE:
if (mIsLoading) {
mAnimPercent += 0.1611113;
int color= (int) mArgbEvaluator.evaluate(mAnimPercent,mTriangleColor,mCircleColor);
mPaint.setColor(color);
// triangle to circle
Path path = new Path();
path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));
if (mAnimPercent >= 1) {
mShape = Shape.SHAPE_CIRCLE;
mIsLoading = false;
mAnimPercent=1;
}
float controlX = mControlX - relativeXFromView(mAnimPercent* mTriangle2Circle)
* genhao3;
float controlY = mControlY - relativeYFromView(mAnimPercent* mTriangle2Circle);
path.quadTo(relativeXFromView(1) - controlX, controlY, relativeXFromView(0.5f + genhao3 / 4), relativeYFromView(0.75f));
path.quadTo(relativeXFromView(0.5f), relativeYFromView(0.75f + 2 * mAnimPercent* mTriangle2Circle), relativeXFromView(0.5f - genhao3 / 4), relativeYFromView(0.75f));
path.quadTo(controlX, controlY, relativeXFromView(0.5f), relativeYFromView(0f));
path.close();
canvas.drawPath(path, mPaint);
invalidate();
} else {
Path path = new Path();
mPaint.setColor(mTriangleColor);
path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));
path.lineTo(relativeXFromView(1), relativeYFromView(genhao3 / 2f));
path.lineTo(relativeXFromView(0), relativeYFromView(genhao3/2f));
mControlX = relativeXFromView(0.5f - genhao3 / 8.0f);
mControlY = relativeYFromView(3 / 8.0f);
mAnimPercent = 0;
path.close();
canvas.drawPath(path, mPaint);
}
break;
case SHAPE_CIRCLE:
if (mIsLoading) {
float magicNumber = mMagicNumber + mAnimPercent;
mAnimPercent += 0.12;
if (magicNumber + mAnimPercent >= 1.9f) {
mShape = Shape.SHAPE_RECT;
mIsLoading = false;
}
int color= (int) mArgbEvaluator.evaluate(mAnimPercent,mCircleColor,mRectColor);
mPaint.setColor(color);
Path path = new Path();
path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));
path.cubicTo(relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(0f),
relativeXFromView(1), relativeYFromView(0.5f - magicNumber / 2),
relativeXFromView(1f), relativeYFromView(0.5f));
path.cubicTo(
relativeXFromView(1), relativeXFromView(0.5f + magicNumber / 2),
relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(1f),
relativeXFromView(0.5f), relativeYFromView(1f));
path.cubicTo(relativeXFromView(0.5f - magicNumber / 2), relativeXFromView(1f),
relativeXFromView(0), relativeYFromView(0.5f + magicNumber / 2),
relativeXFromView(0f), relativeYFromView(0.5f));
path.cubicTo(relativeXFromView(0f), relativeXFromView(0.5f - magicNumber / 2),
relativeXFromView(0.5f - magicNumber / 2), relativeYFromView(0),
relativeXFromView(0.5f), relativeYFromView(0f));
path.close();
canvas.drawPath(path, mPaint);
invalidate();
} else {
mPaint.setColor(mCircleColor);
Path path = new Path();
float magicNumber = mMagicNumber;
path.moveTo(relativeXFromView(0.5f), relativeYFromView(0f));
path.cubicTo(relativeXFromView(0.5f + magicNumber / 2), 0,
relativeXFromView(1), relativeYFromView(magicNumber / 2),
relativeXFromView(1f), relativeYFromView(0.5f));
path.cubicTo(
relativeXFromView(1), relativeXFromView(0.5f + magicNumber / 2),
relativeXFromView(0.5f + magicNumber / 2), relativeYFromView(1f),
relativeXFromView(0.5f), relativeYFromView(1f));
path.cubicTo(relativeXFromView(0.5f - magicNumber / 2), relativeXFromView(1f),
relativeXFromView(0), relativeYFromView(0.5f + magicNumber / 2),
relativeXFromView(0f), relativeYFromView(0.5f));
path.cubicTo(relativeXFromView(0f), relativeXFromView(0.5f - magicNumber / 2),
relativeXFromView(0.5f - magicNumber / 2), relativeYFromView(0),
relativeXFromView(0.5f), relativeYFromView(0f));
mAnimPercent = 0;
path.close();
canvas.drawPath(path, mPaint);
}
break;
case SHAPE_RECT:
if (mIsLoading) {
mAnimPercent += 0.15;
if (mAnimPercent >= 1) {
mShape = Shape.SHAPE_TRIANGLE;
mIsLoading = false;
mAnimPercent = 1;
}
int color= (int) mArgbEvaluator.evaluate(mAnimPercent,mRectColor,mTriangleColor);
mPaint.setColor(color);
Path path = new Path();
path.moveTo(relativeXFromView(0.5f * mAnimPercent), 0);
path.lineTo(relativeYFromView(1 - 0.5f * mAnimPercent), 0);
float distanceX = (mControlX) * mAnimPercent;
float distanceY = (relativeYFromView(1f) - mControlY) * mAnimPercent;
path.lineTo(relativeXFromView(1f) - distanceX, relativeYFromView(1f) - distanceY);
path.lineTo(relativeXFromView(0f) + distanceX, relativeYFromView(1f) - distanceY);
path.close();
canvas.drawPath(path, mPaint);
invalidate();
} else {
mPaint.setColor(mRectColor);
mControlX = relativeXFromView(0.5f - genhao3 / 4);
mControlY = relativeYFromView(0.75f);
Path path = new Path();
path.moveTo(relativeXFromView(0f), relativeYFromView(0f));
path.lineTo(relativeXFromView(1f), relativeYFromView(0f));
path.lineTo(relativeXFromView(1f), relativeYFromView(1f));
path.lineTo(relativeXFromView(0f), relativeYFromView(1f));
path.close();
mAnimPercent = 0;
canvas.drawPath(path, mPaint);
}
break;
}
}
private float relativeXFromView(float percent) {
return getWidth() * percent;
}
private float relativeYFromView(float percent) {
return getHeight() * percent;
}
public void changeShape() {
mIsLoading = true;
invalidate();
}
public void setShape(Shape shape){
mIsLoading = true;
mShape = shape;
invalidate();
}
public enum Shape {
SHAPE_TRIANGLE, SHAPE_RECT, SHAPE_CIRCLE
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if(visibility==VISIBLE){
invalidate();
}
}
public Shape getShape() {
return mShape;
}
private int getColor(Context context, int id) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return context.getColor(id);
} else {
return context.getResources().getColor(id);
}
}
}

Step 6: Creating the DialogDemoActivity.java file

Use the ScrollShow set functions as shown below so as to enable the use of Header movement in the android application.

package com.dennism;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.dennism.widget.ShapeLoadingDialog;
public class DialogDemoActivity extends ActionBarActivity {
private ShapeLoadingDialog shapeLoadingDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog_demo);
shapeLoadingDialog = new ShapeLoadingDialog.Builder(this)
.loadText("Loading...")
.build();
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shapeLoadingDialog.show();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_dialog_demo, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

Step 7: Creating the ViewDemoActivity.java file

Go to the onCreate function as shown below. It is responsible for making objects move according to a preset program like rotating the different shapes.

package com.dennism;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class ViewDemoActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_demo);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_view_demo, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

Step 8: Creating the MainActivity.java file

Now, come to your MainActivity.java file. We’ll declare two buttons to display ViewDemoActivity and DialogDemoActivity. The other important function to use in the main activity is the onCreateOptionsMenu function. It is responsible for inflating the menu; this adds items to the action bar if it is present.

Finally, your final MainActivity.java will be like this.

package com.dennism;
import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.startActivity(new Intent(MainActivity.this,ViewDemoActivity.class));
}
});
findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
MainActivity.this.startActivity(new Intent(MainActivity.this,DialogDemoActivity.class));
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
view raw MainActivity.java hosted with ❤ by GitHub

Above all, use the onOptionsItemSelected function which will Handle action bar item clicks here. The action bar will automatically handle clicks on the Home/Up button, so long as you specify a parent activity in AndroidManifest.xml.

Future Directions

Finally, the future directions involve displaying the shape loading view inside an app that requires the progress bar to be displayed while waiting for the next step to process; therefore making it able for the user to proceed to the next step successfully.

Learning Strategies and Tools

The most useful tool used for acquiring critical information for the development of this project is the android developer manual. Zeroing in on the shape loading view is responsible for displaying ecstatically the app is in progress. Instead of the spinner progress bar which is commonly used.

In conclusion, we have learned about how your app can use shape loading view in android.  Activities now have to implement the different functions in their respective activities to implement the shape loading view in android. 

Reflective Analysis

Figuring out how to utilize shape loading view in android was a great learning experience. It is an astonishing instrument that makes the comprehension ScrollView endpoints simple

One of its most common uses in android is used to show activity statuses such as status analysis or file downloading etc. On Android, by default, the progress bar will be displayed as a rotating wheel but if we want it to be displayed as a horizontal bar then we need to use the style attribute as horizontal.   

In conclusion, I spent 72 hours finishing the project and the blog.  Eventually, everything is available in this GitHub repository.

Link to the previous post: https://blog.learningdollars.com/2020/09/16/how-to-check-internet-connection-programatically-on-android-from-a-button-click-in-kotlin

That’s all for this tutorial!