效果
红色点是贝塞尔曲线的控制点。方便查看
代码
BottomNavigationBar
package com.trs.app.gzcz.content_manage.ui.test;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;
import com.trs.news.R;
import com.trs.nmip.common.util.AppUtil;
import java.util.ArrayList;
import java.util.List;
public class BottomNavigationBar extends LinearLayout implements View.OnClickListener {
private Paint paint;
private Path path;
private float width;
private int currentPosition = 0;
private onBottomNavClickListener listener;
// private String[] tabText = {"打卡", "发现", "消息", "我的"};
//未选中icon
private int[] normalIcon = {R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish};
//选中时icon
private int[] selectIcon = {R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish, R.drawable.icon_edit_option_publish};
private ImageView img1, img2, imgCenter, img3, img4;
private ViewPager viewPager;
private Paint testPaint;
public BottomNavigationBar(Context context) {
super(context);
init(context);
}
public BottomNavigationBar(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
path = new Path();
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setColor(Color.WHITE);
View view = LayoutInflater.from(context).inflate(R.layout.layout_test, this);
img1 = view.findViewById(R.id.first);
img2 = view.findViewById(R.id.second);
imgCenter = view.findViewById(R.id.centerIcon);
img3 = view.findViewById(R.id.third);
img4 = view.findViewById(R.id.forth);
setWillNotDraw(false);
//2、通过Resources获取
DisplayMetrics dm = getResources().getDisplayMetrics();
width = dm.widthPixels;
img1.setOnClickListener(this::onClick);
img2.setOnClickListener(this::onClick);
img3.setOnClickListener(this::onClick);
img4.setOnClickListener(this::onClick);
imgCenter.setOnClickListener(this::onClick);
testPaint = new Paint();
testPaint.setColor(Color.RED);
testPaint.setStrokeWidth(AppUtil.dip2px(3));
testPaint.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
paint.setColor(Color.WHITE);
paint.setShadowLayer(30,0,20,Color.BLACK);
path.moveTo(0, dip2px(28));
path.lineTo(dip2px(150), dip2px(28));
pList.clear();
pList.add(new Point(dip2px(150), dip2px(28)));
path.quadTo(width / 2 - dip2px(30), dip2px(28), width / 2 - dip2px(25), dip2px(18));
pList.add(new Point(width / 2 - dip2px(30), dip2px(28)));
pList.add(new Point(width / 2 - dip2px(25), dip2px(18)));
path.quadTo(width / 2, -20, width / 2 + dip2px(25), dip2px(18));
pList.add(new Point(width / 2, -20));
pList.add(new Point(width / 2 + dip2px(25), dip2px(18)));
path.quadTo(width / 2 + dip2px(30), dip2px(28), width - dip2px(150), dip2px(28));
pList.add(new Point(width / 2 + dip2px(30), dip2px(28)));
pList.add(new Point(width - dip2px(150), dip2px(28)));
path.lineTo(width, dip2px(28));
path.lineTo(width, dip2px(71));
path.lineTo(0, dip2px(71));
path.close();
canvas.drawPath(path, paint);
super.onDraw(canvas);
for(Point p:pList){
canvas.drawPoint(p.x,p.y,testPaint);
}
}
List<Point> pList=new ArrayList<>();
private class Point{
float x,y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
}
/**
* 根据屏幕的分辨率从 dp 的单位 转成为 px(像素)
*/
private int dip2px(float dpValue) {
final float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
public void setUpWithViewPager(ViewPager viewPager) {
this.viewPager = viewPager;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.first:
if (currentPosition == 0) break;
setUnSelect(currentPosition);
currentPosition = 0;
viewPager.setCurrentItem(currentPosition,true);
img1.setImageResource(selectIcon[currentPosition]);
break;
case R.id.second:
if (currentPosition == 1) break;
setUnSelect(currentPosition);
currentPosition = 1;
viewPager.setCurrentItem(currentPosition,true);
img2.setImageResource(selectIcon[currentPosition]);
break;
case R.id.third:
if (currentPosition == 2) break;
setUnSelect(currentPosition);
currentPosition = 2;
viewPager.setCurrentItem(currentPosition,true);
img3.setImageResource(selectIcon[currentPosition]);
break;
case R.id.forth:
if (currentPosition == 3) break;
setUnSelect(currentPosition);
currentPosition = 3;
viewPager.setCurrentItem(currentPosition,true);
img4.setImageResource(selectIcon[currentPosition]);
break;
case R.id.centerIcon:
if (listener != null) listener.onCenterIconClick();
break;
}
}
private void setUnSelect(int position) {
switch (position) {
case 0:
img1.setImageResource(normalIcon[0]);
break;
case 1:
img2.setImageResource(normalIcon[1]);
break;
case 2:
img3.setImageResource(normalIcon[2]);
break;
case 3:
img4.setImageResource(normalIcon[3]);
break;
}
}
public interface onBottomNavClickListener {
void onCenterIconClick();
}
public void setOnListener(onBottomNavClickListener listener){
this.listener = listener;
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="71dp"
android:clipChildren="false"
android:paddingBottom="10dp"
android:background="#00000000"
android:gravity="bottom"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:id="@+id/first"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="1"
android:src="@drawable/icon_edit_option_publish"/>
<ImageView
android:id="@+id/second"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="1"
android:src="@drawable/icon_edit_option_publish"/>
<ImageView
android:layout_width="44dp"
android:layout_height="44dp"
android:src="@drawable/icon_tab_publish"
android:layout_marginBottom="0dp"
android:id="@+id/centerIcon"/>
<ImageView
android:id="@+id/third"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="1"
android:src="@drawable/icon_edit_option_publish" />
<ImageView
android:id="@+id/forth"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_weight="1"
android:src="@drawable/icon_edit_option_publish"/>
</LinearLayout>
用到的图标
测试布局
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
tools:context="com.trs.app.gzcz.content_manage.ui.test.TestActivity">
<com.trs.app.gzcz.content_manage.ui.test.BottomNavigationBar
android:layout_width="match_parent"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"/>
</RelativeLayout>