Skip to content

Commit dee38fc

Browse files
committed
Android tutorial CurvedBottomNavigationView Best Example
0 parents  commit dee38fc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1086
-0
lines changed

.gitignore

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea/caches/build_file_checksums.ser
5+
/.idea/libraries
6+
/.idea/modules.xml
7+
/.idea/workspace.xml
8+
.DS_Store
9+
/build
10+
/captures
11+
.externalNativeBuild

.idea/codeStyles/Project.xml

+29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+38
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations.xml

+12
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CurvedBottomNavigationView.zip

138 KB
Binary file not shown.

app/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

app/build.gradle

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
apply plugin: 'com.android.application'
2+
3+
android {
4+
compileSdkVersion 28
5+
defaultConfig {
6+
applicationId "android.tutorial.curvedbottombar"
7+
minSdkVersion 21
8+
targetSdkVersion 28
9+
versionCode 1
10+
versionName "1.0"
11+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12+
}
13+
buildTypes {
14+
release {
15+
minifyEnabled false
16+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17+
}
18+
}
19+
}
20+
21+
dependencies {
22+
implementation fileTree(dir: 'libs', include: ['*.jar'])
23+
implementation 'androidx.appcompat:appcompat:1.0.2'
24+
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
25+
implementation 'com.google.android.material:material:1.1.0-alpha01'
26+
testImplementation 'junit:junit:4.12'
27+
androidTestImplementation 'androidx.test:runner:1.1.0'
28+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
29+
implementation 'com.sdsmdg.harjot:vectormaster:1.1.3'
30+
31+
}

app/proguard-rules.pro

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package android.tutorial.curvedbottombar;
2+
3+
import android.content.Context;
4+
import androidx.test.InstrumentationRegistry;
5+
import androidx.test.runner.AndroidJUnit4;
6+
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
10+
import static org.junit.Assert.*;
11+
12+
/**
13+
* Instrumented test, which will execute on an Android device.
14+
*
15+
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
16+
*/
17+
@RunWith(AndroidJUnit4.class)
18+
public class ExampleInstrumentedTest {
19+
@Test
20+
public void useAppContext() {
21+
// Context of the app under test.
22+
Context appContext = InstrumentationRegistry.getTargetContext();
23+
24+
assertEquals("android.tutorial.curvedbottomnavigationview", appContext.getPackageName());
25+
}
26+
}

app/src/main/AndroidManifest.xml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="android.tutorial.curvedbottombar">
3+
4+
<application
5+
android:allowBackup="true"
6+
android:icon="@mipmap/ic_launcher"
7+
android:label="@string/app_name"
8+
android:roundIcon="@mipmap/ic_launcher_round"
9+
android:supportsRtl="true"
10+
android:theme="@style/AppTheme" >
11+
12+
<activity android:name=".MainActivity">
13+
<intent-filter>
14+
<action android:name="android.intent.action.MAIN"/>
15+
16+
<category android:name="android.intent.category.LAUNCHER"/>
17+
</intent-filter>
18+
</activity>
19+
</application>
20+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package android.tutorial.curvedbottombar;
2+
3+
import android.content.Context;
4+
import android.graphics.Canvas;
5+
import android.graphics.Color;
6+
import android.graphics.Paint;
7+
import android.graphics.Path;
8+
import android.graphics.Point;
9+
import com.google.android.material.bottomnavigation.BottomNavigationView;
10+
import android.util.AttributeSet;
11+
12+
public class CurvedBottomNavigationView extends BottomNavigationView {
13+
private Path mPath;
14+
private Paint mPaint;
15+
16+
/** the CURVE_CIRCLE_RADIUS represent the radius of the fab button */
17+
public final int CURVE_CIRCLE_RADIUS = 256 / 4;
18+
// the coordinates of the first curve
19+
public Point mFirstCurveStartPoint = new Point();
20+
public Point mFirstCurveEndPoint = new Point();
21+
public Point mFirstCurveControlPoint2 = new Point();
22+
public Point mFirstCurveControlPoint1 = new Point();
23+
24+
//the coordinates of the second curve
25+
@SuppressWarnings("FieldCanBeLocal")
26+
public Point mSecondCurveStartPoint = new Point();
27+
public Point mSecondCurveEndPoint = new Point();
28+
public Point mSecondCurveControlPoint1 = new Point();
29+
public Point mSecondCurveControlPoint2 = new Point();
30+
public int mNavigationBarWidth;
31+
public int mNavigationBarHeight;
32+
33+
public CurvedBottomNavigationView(Context context) {
34+
super(context);
35+
init();
36+
}
37+
38+
public CurvedBottomNavigationView(Context context, AttributeSet attrs) {
39+
super(context, attrs);
40+
init();
41+
}
42+
43+
public CurvedBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
44+
super(context, attrs, defStyleAttr);
45+
init();
46+
}
47+
48+
private void init() {
49+
mPath = new Path();
50+
mPaint = new Paint();
51+
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
52+
mPaint.setColor(Color.WHITE);
53+
setBackgroundColor(Color.TRANSPARENT);
54+
}
55+
56+
@Override
57+
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
58+
super.onLayout(changed, left, top, right, bottom);
59+
60+
}
61+
62+
@Override
63+
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
64+
super.onSizeChanged(w, h, oldw, oldh);
65+
// get width and height of navigation bar
66+
// Navigation bar bounds (width & height)
67+
mNavigationBarWidth = getWidth();
68+
mNavigationBarHeight = getHeight();
69+
// the coordinates (x,y) of the start point before curve
70+
mFirstCurveStartPoint.set((mNavigationBarWidth / 2) - (CURVE_CIRCLE_RADIUS * 2) - (CURVE_CIRCLE_RADIUS / 3), 0);
71+
// the coordinates (x,y) of the end point after curve
72+
mFirstCurveEndPoint.set(mNavigationBarWidth / 2, CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4));
73+
// same thing for the second curve
74+
mSecondCurveStartPoint = mFirstCurveEndPoint;
75+
mSecondCurveEndPoint.set((mNavigationBarWidth / 2) + (CURVE_CIRCLE_RADIUS * 2) + (CURVE_CIRCLE_RADIUS / 3), 0);
76+
77+
// the coordinates (x,y) of the 1st control point on a cubic curve
78+
mFirstCurveControlPoint1.set(mFirstCurveStartPoint.x + CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4), mFirstCurveStartPoint.y);
79+
// the coordinates (x,y) of the 2nd control point on a cubic curve
80+
mFirstCurveControlPoint2.set(mFirstCurveEndPoint.x - (CURVE_CIRCLE_RADIUS * 2) + CURVE_CIRCLE_RADIUS, mFirstCurveEndPoint.y);
81+
82+
mSecondCurveControlPoint1.set(mSecondCurveStartPoint.x + (CURVE_CIRCLE_RADIUS * 2) - CURVE_CIRCLE_RADIUS, mSecondCurveStartPoint.y);
83+
mSecondCurveControlPoint2.set(mSecondCurveEndPoint.x - (CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4)), mSecondCurveEndPoint.y);
84+
}
85+
86+
@Override
87+
protected void onDraw(Canvas canvas) {
88+
super.onDraw(canvas);
89+
mPath.reset();
90+
mPath.moveTo(0, 0);
91+
mPath.lineTo(mFirstCurveStartPoint.x, mFirstCurveStartPoint.y);
92+
93+
mPath.cubicTo(mFirstCurveControlPoint1.x, mFirstCurveControlPoint1.y,
94+
mFirstCurveControlPoint2.x, mFirstCurveControlPoint2.y,
95+
mFirstCurveEndPoint.x, mFirstCurveEndPoint.y);
96+
97+
mPath.cubicTo(mSecondCurveControlPoint1.x, mSecondCurveControlPoint1.y,
98+
mSecondCurveControlPoint2.x, mSecondCurveControlPoint2.y,
99+
mSecondCurveEndPoint.x, mSecondCurveEndPoint.y);
100+
101+
mPath.lineTo(mNavigationBarWidth, 0);
102+
mPath.lineTo(mNavigationBarWidth, mNavigationBarHeight);
103+
mPath.lineTo(0, mNavigationBarHeight);
104+
mPath.close();
105+
106+
canvas.drawPath(mPath, mPaint);
107+
}
108+
}

0 commit comments

Comments
 (0)