贝塞尔曲线实现底部导航栏

效果

红色点是贝塞尔曲线的控制点。方便查看
在这里插入图片描述

代码

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>

参考来源
Android底部导航栏突出(贝塞尔曲线)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值