android底部导航,中间凸起底部导航

这篇博客介绍了如何利用二阶贝塞尔曲线在Android中创建一个底部导航栏,其中中间部分呈凸起状。作者详细解释了贝塞尔曲线的绘制原理,并提供了具体的代码实现,包括设置关键点坐标来绘制三条曲线,最终形成平滑的凸起效果。文章还分享了项目的GitHub链接,供读者参考和交流。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做一个项目,底部导航中间部分需要凸起,本来一开始我是用一个圆形的背景的但是这样子边上就会有很生硬的边角.

比如就像这样:

这样子就很不美观,于是就用贝斯尔曲线重新绘制一个带有弧形的

首先我们是要知道贝塞尔曲线是怎么绘制的,这里的话我们是用到了二阶的贝塞尔曲线,由二阶贝赛尔公式:B(t)=(1 - t)²Po + 2t(1 - t)P1 + t²P2,t∈[0,1];

在这里Po是起点,P2是终点,P1是控制点,我们给公式做一个分解因式的转换

            B(t)= (1-t)[(1-t)Po + tP1] + t[(1-t)P1 + tP2]

通过分解因式,我们发现其实二阶曲线公式是一阶曲线公式的组合,首先各自取得(Po、P1)和(P1、P2)的一阶曲线值,然后再将两个值作为一阶曲线的起点和终点计算得到B(t)得到整个二阶曲线的值

根据下面这张图,我们可以得逞,画一条二阶贝赛尔曲线是需要确定三个点,所以由此得出,我们以下分析:
首先我们这个凸起一共有三个弯曲,所以我们需要画三条贝塞尔曲线,
第一条曲线先把A点确定,再画B点,最后在画C点,第二条曲线由于第一条和第二条是首尾相接的,那么第二条的起点也就是第一条曲线的终点坐标,最后第三条也是跟前面的一样

 

代码如下:

    @Override
    protected void onDraw(Canvas canvas) {
        int high = 90;//底部导航的高度
        int marginTop = 30;//剧顶边高度
        
        int x1 = (int)width/3; //120 参考1080/3
        int x2 = (int)(width/2.8); //130  参考1080/2.8
        int x3 = (int)(width/2.6); //140  参考1080/2.6

        a.x = x1; //dip2px(120)
        a.y = dip2px(marginTop);
        b.x = x2; //dip2px(130)
        b.y = dip2px(marginTop);
        c.x = x3; //dip2px(140)
        c.y = dip2px(marginTop-10);

        a2.x = c.x;
        a2.y = c.y;
        b2.x = width / 2;
        b2.y = dip2px(-10);
        c2.x = width - x3; //dip2px(140)
        c2.y = dip2px(marginTop-10);

        a3.x =  c2.x;
        a3.y =  c2.y;
        b3.x =  width - x2; //dip2px(130)
        b3.y = dip2px(marginTop);
        c3.x = width - x1; //dip2px(120)
        c3.y = dip2px(marginTop);

        paint.setColor(Color.WHITE);
        paint.setShadowLayer(30, 0, 20, Color.parseColor("#d4d5d9"));

        //moveTo 用来移动画笔
        path.moveTo(0, dip2px(marginTop));//设置下一个轮廓线的起始点(x,y)。第一个点

        path.lineTo(a.x, a.y); //绘制到贝塞尔曲线第一个点 也就是a1点

        path.quadTo(b.x, b.y, c.x, c.y);//第左边曲线
        path.quadTo(b2.x, b2.y, c2.x, c2.y);//中间曲线
        path.quadTo(b3.x , b3.y, c3.x, c3.y );//第右边曲线

        path.lineTo(width, dip2px(marginTop)); 
        path.lineTo(width, dip2px(high));
        path.lineTo(0, dip2px(high));

        path.close();
        canvas.drawPath(path, paint); 

        super.onDraw(canvas);
    }

运行效果:

 

 到这我们的中间凸起的导航栏就完成啦!!!

最后附上项目地址:​​​​​​GitHub - super963883929/NavigationBar: 底部导航,中间凸起底部导航,贝塞尔曲线导航栏,弧形导航栏​​​​​​底部导航,中间凸起底部导航,贝塞尔曲线导航栏,弧形导航栏. Contribute to super963883929/NavigationBar development by creating an account on GitHub.https://github.com/super963883929/NavigationBar

感兴趣的朋友可以去下载看看,有问题大家也可以交流一下,新手发帖,多多包涵 

要实现 BottomNavigationView 中间凸起的效果,可以使用第三方库或者自定义控件实现。以下是自定义控件的实现方式: 1. 创建一个自定义控件类,继承自 BottomNavigationView。 2. 在自定义控件类的构造函数中,调用 init() 方法初始化控件。 3. 在 init() 方法中,设置 BottomNavigationView 的 ItemIconTintList、ItemTextColor 和 ItemBackgroundResource 属性,以及添加中间凸起的 Item。 4. 在自定义控件类中,重写 onMeasure() 方法,使中间凸起的 Item 占据 BottomNavigationView 的一定比例。 5. 在自定义控件类中,重写 onDraw() 方法,绘制中间凸起的 Item。 6. 在布局文件中使用自定义控件。 具体实现细节可以参考以下代码示例: ```java public class CustomBottomNavigationView extends BottomNavigationView { private static final int ITEM_SIZE = 5; // BottomNavigationView 的 Item 数量 private static final int MIDDLE_ITEM_INDEX = 2; // 中间凸起的 Item 索引 private static final int MIDDLE_ITEM_SIZE = 80; // 中间凸起的 Item 大小 private Paint mPaint; private Path mPath; public CustomBottomNavigationView(Context context) { super(context); init(); } public CustomBottomNavigationView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 设置 BottomNavigationView 的 ItemIconTintList、ItemTextColor 和 ItemBackgroundResource 属性 int[][] states = new int[][]{ new int[]{-android.R.attr.state_checked}, new int[]{android.R.attr.state_checked}, }; int[] colors = new int[]{ Color.GRAY, Color.BLUE, }; ColorStateList csl = new ColorStateList(states, colors); setItemIconTintList(csl); setItemTextColor(csl); setBackgroundResource(R.color.white); // 添加中间凸起的 Item Menu menu = getMenu(); menu.add(Menu.NONE, R.id.item_middle, Menu.NONE, "") .setIcon(R.drawable.ic_add) .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); // 初始化画笔和路径 mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(getResources().getColor(R.color.white)); mPath = new Path(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 计算中间凸起的 Item 大小 int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int itemWidth = width / ITEM_SIZE; int middleItemWidth = MIDDLE_ITEM_SIZE * (ITEM_SIZE - 2) / ITEM_SIZE; int middleItemHeight = MIDDLE_ITEM_SIZE / 2; // 设置中间凸起的 Item 大小 MenuItem middleItem = getMenu().findItem(R.id.item_middle); middleItem.setIcon(R.drawable.ic_add); middleItem.setWidth(middleItemWidth); middleItem.setHeight(middleItemHeight); // 设置中间凸起的 Item 占据 BottomNavigationView 的一定比例 ViewGroup.LayoutParams layoutParams = getLayoutParams(); layoutParams.height = height + middleItemHeight; setLayoutParams(layoutParams); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 绘制中间凸起的 Item float centerX = getWidth() / ITEM_SIZE * MIDDLE_ITEM_INDEX; float centerY = getHeight() / 2; float radius = MIDDLE_ITEM_SIZE / 2; mPath.reset(); mPath.moveTo(centerX - radius, centerY - radius); mPath.lineTo(centerX + radius, centerY - radius); mPath.lineTo(centerX, centerY + radius); mPath.close(); canvas.drawPath(mPath, mPaint); } } ``` 使用自定义控件时,只需在布局文件中引用即可: ```xml <com.example.CustomBottomNavigationView android:id="@+id/bottom_navigation_view" android:layout_width="match_parent" android:layout_height="wrap_content" app:menu="@menu/bottom_navigation_menu" /> ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值