Настраиваемая форма нижней панели в android

Кастомная нижняя панель в android

Однажды меня попросили создать приложение с необычным дизайном нижней панели BottomNavigationView :
Кастомная нижняя панель в android
Изогнутый BottomNavigationView
Я никогда ранее не делал ничего подобного, поэтому начал гуглить на предмет создания custom view. После поисков и советов коллег, я понял, что это всего лишь разновидность кривой Безье.Рекомендую так же прочесть мою статью Разработка приложения-галереи под Android на Kotlin

Кривая Безье

Если вы когда-либо использовали компьютерные программы для рисования, вы скорее всего использовали кривые Безье, даже не подозревая об этом. 
Кастомная нижняя панель в android
пример кривой Безье в Adobe Illustrator
Я нашёл интересную статью, в которой был описан необходимый мне тип кривой, рекомендую её прочитать. Там же есть утилита для работы с кривыми.Кривая, отражающая нужный мне дизайн, оказалась кубической кривой Безье.
Кастомная нижняя панель в android
Кубические кривые определяются четырьмя опорными точками. Первая и последняя определяют положение концов кривой, а вторая и третья точки отвечают за направление кривой.Перейдём к коду и увидим, как создавать кривые Безье в android.Вначале создадим собственный view, расширяющий BottomNavigationView, чтобы взять весь его функционал и сконцентрироваться только на дизайне.
public class CurvedBottomNavigationView extends BottomNavigationView {
    public CurvedBottomNavigationView(Context context) {
        super(context);
        init();
    }
    public CurvedBottomNavigationView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public CurvedBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
        mPath = new Path();
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setColor(Color.WHITE);
        setBackgroundColor(Color.TRANSPARENT);
    }
}
Метод init()в этом коде только инициализирует объекты path и paint.Роль path — позволить нам рисовать геометрические формы, в том числе кривые Безье. Path рисует линию от точки до точки. Обычный 
BottomNavigationView в форме прямоугольника, поэтому используя Path мы перерисуем его с помощью кривых.
Кастомная нижняя панель в android
Позиции точек
Сначала инициализируем позиции наших точек. Они зависят от ширины и высоты view. Здесь P1 — начальная точка рисования, P2 — начало первой кривой, P3 — конец первой кривой и начало второй, а P4 — окончание второй кривой. Никогда не делайте расчёты в методе onDraw()— он вызывается постоянно и это просто убьёт производительность приложения. Я делаю расчёты в методе onSizeChanged(), вызываемом при изменении размера view, поэтому на производительности это не должно сильно сказаться
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // получаем ширину и высоту navigation bar
         mNavigationBarWidth = getWidth();
         mNavigationBarHeight = getHeight();
        // координаты (x,y) начальной точки до кривой
        mFirstCurveStartPoint.set((mNavigationBarWidth / 2) - (CURVE_CIRCLE_RADIUS * 2) - (CURVE_CIRCLE_RADIUS / 3), 0);
        // координаты (x,y) конечной точки после кривой
        mFirstCurveEndPoint.set(mNavigationBarWidth / 2, CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4));
        // то же самое для второй кривой
        mSecondCurveStartPoint = mFirstCurveEndPoint;
        mSecondCurveEndPoint.set((mNavigationBarWidth / 2) + (CURVE_CIRCLE_RADIUS * 2) + (CURVE_CIRCLE_RADIUS / 3), 0);

        // координаты (x,y) первой опорной точки на кубической кривой
        mFirstCurveControlPoint1.set(mFirstCurveStartPoint.x + CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4), mFirstCurveStartPoint.y);
        // координаты (x,y) второй опорной точки
        mFirstCurveControlPoint2.set(mFirstCurveEndPoint.x - (CURVE_CIRCLE_RADIUS * 2) + CURVE_CIRCLE_RADIUS, mFirstCurveEndPoint.y);

        mSecondCurveControlPoint1.set(mSecondCurveStartPoint.x + (CURVE_CIRCLE_RADIUS * 2) - CURVE_CIRCLE_RADIUS, mSecondCurveStartPoint.y);
        mSecondCurveControlPoint2.set(mSecondCurveEndPoint.x - (CURVE_CIRCLE_RADIUS + (CURVE_CIRCLE_RADIUS / 4)), mSecondCurveEndPoint.y);
    }
Перейдём к более интересному. Для начала обнулим (reset) path для удаления линий и кривых из неё, затем переместим её в начальную точку P1, используя метод moveTo(x,y), и нарисуем первую линию между P1 и P2, используя lineTo(x,y), это добавит линию с последней точки до заданной точки. Так как у нас пока нет последней точки, укажем moveTo(0,0).Для рисования кубических кривых мы должны использовать метод cubicTo(x1,y1,x2,y2,x3,y3), где первая и вторая точки (x1,y1) (x2,y2) контролируют наклон. Для проверки корректности точек можно использовать эту утилиту. Так же отрисуем вторую кривую и так далее всю панель.
 @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        
        //расчет точки 
        
        mPath.reset();
        mPath.moveTo(0, 0);
        mPath.lineTo(mFirstCurveStartPoint.x, mFirstCurveStartPoint.y);

        mPath.cubicTo(mFirstCurveControlPoint1.x, mFirstCurveControlPoint1.y,
                mFirstCurveControlPoint2.x, mFirstCurveControlPoint2.y,
                mFirstCurveEndPoint.x, mFirstCurveEndPoint.y);

        mPath.cubicTo(mSecondCurveControlPoint1.x, mSecondCurveControlPoint1.y,
                mSecondCurveControlPoint2.x, mSecondCurveControlPoint2.y,
                mSecondCurveEndPoint.x, mSecondCurveEndPoint.y);

        mPath.lineTo(mNavigationBarWidth, 0);
        mPath.lineTo(mNavigationBarWidth, mNavigationBarHeight);
        mPath.lineTo(0, mNavigationBarHeight);
        mPath.close();
    }
Наконец, мы можем рисовать с помощью объекта canvas (канва). Канва содержит несколько методов рисования, и нам подходит canvas.drawPath(Path path, Paint paint).
  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
    }
Хорошей разработки!Код примеров вы сможете найти в моём Github и на Java и на Kotlin. Только выберите правильную ветку.По материалам: «How I drew custom shapes in bottom bar»Также по разработке под android рекомендую почитать «Разработка приложения-галереи под Android на Kotlin»

Похожие статьи

Кастомная нижняя панель в android

Разработчик: java, kotlin, c#, javascript, dart, 1C, python, php.

Пишите: @ighar. Buy me a coffee, please :).

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Загрузка...

Leave a Comment

Adblock detector