返回顶部
首页 > 资讯 > 移动开发 >Android自定义字母导航栏
  • 587
分享到

Android自定义字母导航栏

字母Android 2022-06-06 11:06:27 587人浏览 泡泡鱼
摘要

本文实例为大家分享了Android字母导航栏的具体代码,供大家参考,具体内容如下 效果 实现逻辑 明确需求 字母导航栏在实际开发中还是比较多见的,城市选择、名称选择等等可能

本文实例为大家分享了Android字母导航栏的具体代码,供大家参考,具体内容如下

效果

实现逻辑

明确需求

字母导航栏在实际开发中还是比较多见的,城市选择、名称选择等等可能需要到。 现在要做到的就是在滑动控件过程中可以有内容以及 下标的回调,方便处理其他逻辑!

整理思路

1、确定控件的尺寸,防止内容显示不全。相关的逻辑在onMeasure()方法中处理;
2、绘制显示的内容,在按下和抬起不同状态下文字、背景的颜色。相关逻辑在onDraw()方法中;
3、滑动事件的处理以及事件回调。相关逻辑在onTouchEvent()方法中;

动手实现

在需求明确、思路清晰的情况下就要开始动手实现(需要了解自定义View的一些基础api)。核心代码就onDraw()中。在代码中有思路和注释,可以结合代码一起看看。如果有疑惑、优化、错误的地方请在评论区提出,共同进步!

完整代码



public class CustomLetterNavigationView extends View {
  private static final String TAG = "CustomLetterNavigation";
  //导航内容
  private String[] mNavigationContent;
  //导航栏内容间隔
  private float mContentDiv;
  //导航栏文字大小
  private float mContentTextSize;
  //导航栏文字颜色
  private int mContentTextColor;
  //导航栏按下时背景颜色
  private int mBackgroundColor;
  //导航栏按下时圆角度数
  private int mBackGroundAngle = 0;
  //导航栏按下时文字颜色
  private int mDownContentTextColor;
  private TextPaint mTextPaint;
  private Paint mPaintBackgrount;
  private boolean mEventActionState = false;
  private String mCurrentLetter = "";
  private OnNavigationScrollerListener mOnNavigationScrollerListener;
  private final RectF mRectF = new RectF();
  public CustomLetterNavigationView(Context context) {
    this(context, null);
  }
  public CustomLetterNavigationView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
  }
  public CustomLetterNavigationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initDefaultData();//初始化默认数据
    initAttrs(context, attrs);
  }
  @Override
  protected void onDraw(canvas canvas) {
    
    int mViewWidth = getWidth();
    //绘制背景
    mRectF.set(0, 0, mViewWidth, getHeight());
    if (mEventActionState) {
      mTextPaint.setColor(mDownContentTextColor);
      mPaintBackgrount.setColor(mBackgroundColor);
      canvas.drawRoundRect(mRectF, mBackGroundAngle, mBackGroundAngle, mPaintBackgrount);
    } else {
      mTextPaint.setColor(mContentTextColor);
      mPaintBackgrount.setColor(Color.TRANSPARENT);
      Drawable mBackground = getBackground();
      if (mBackground instanceof ColorDrawable) {
        mPaintBackgrount.setColor(((ColorDrawable) mBackground).getColor());
      }
      canvas.drawRoundRect(mRectF, mBackGroundAngle, mBackGroundAngle, mPaintBackgrount);
    }
    //绘制文本
    float textX = mViewWidth / 2;
    //X轴坐标
    int contentLenght = getContentLength();
    //Y轴坐标(这里在测量的时候多加入了两个间隔高度要减去,同时还有Padding值)
    float heightShould = (getHeight() - mContentDiv * 2 - getPaddingTop() - getPaddingBottom()) / contentLenght;
    for (int i = 0; i < contentLenght; i++) {
      //计算Y轴的坐标
      float startY = ((i + 1) * heightShould) + getPaddingTop();
      //绘制文字
      canvas.drawText(mNavigationContent[i], textX, startY, mTextPaint);
    }
  }
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    
    float mEventY = event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        //手指按下的时候,修改Enent状态、重绘背景、触发回调
        mEventActionState = true;
        invalidate();
        if (mOnNavigationScrollerListener != null) {
          mOnNavigationScrollerListener.onDown();
        }
        scrollCount(mEventY);
        break;
      case MotionEvent.ACTION_MOVE:
        scrollCount(mEventY);
        break;
      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        //手指离开的时候,修改Enent状态、重绘背景、触发回调
        mEventActionState = false;
        invalidate();
        if (mOnNavigationScrollerListener != null) {
          mOnNavigationScrollerListener.onUp();
        }
        break;
    }
    return true;
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
    int widhtMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    //获取控件的尺寸
    int actualWidth = MeasureSpec.getSize(widthMeasureSpec);
    int actualHeight = MeasureSpec.getSize(heightMeasureSpec);
    int contentLegth = getContentLength();
    //计算一个文字的尺寸
    Rect mRect = measureTextSize();
    //内容的最小宽度
    float contentWidth = mRect.width() + mContentDiv * 2;
    //内容的最小高度
    float contentHeight = mRect.height() * contentLegth + mContentDiv * (contentLegth + 3);
    if (MeasureSpec.AT_MOST == widhtMode) {
      //宽度包裹内容
      actualWidth = (int) contentWidth + getPaddingLeft() + getPaddingRight();
    } else if (MeasureSpec.EXACTLY == widhtMode) {
      //宽度限制
      if (actualWidth < contentWidth) {
        actualWidth = (int) contentWidth + getPaddingLeft() + getPaddingRight();
      }
    }
    if (MeasureSpec.AT_MOST == heightMode) {
      //高度包裹内容
      actualHeight = (int) contentHeight + getPaddingTop() + getPaddingBottom();
    } else if (MeasureSpec.EXACTLY == widhtMode) {
      //高度限制
      if (actualHeight < contentHeight) {
        actualHeight = (int) contentHeight + getPaddingTop() + getPaddingBottom();
      }
    }
    setMeasuredDimension(actualWidth, actualHeight);
  }
  
  private void initDefaultData() {
    mNavigationContent = new String[]{"搜", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
    mContentDiv = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
    mContentTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics());
    mContentTextColor = Color.parseColor("#333333");
    mDownContentTextColor = Color.WHITE;
    mBackgroundColor = Color.parseColor("#d7d7d7");
    mBackGroundAngle = 0;
    //绘制文字画笔
    mTextPaint = new TextPaint();
    mTextPaint.setAntiAlias(true);
    mTextPaint.setTextSize(mContentTextSize);
    mTextPaint.setColor(mContentTextColor);
    mTextPaint.setTextAlign(Paint.Align.CENTER);
    //绘制背景画笔
    mPaintBackgrount = new Paint();
    mPaintBackgrount.setAntiAlias(true);
    mPaintBackgrount.setStyle(Paint.Style.FILL);
  }
  
  private void initAttrs(Context context, AttributeSet attrs) {
    TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLetterNavigationView);
    mContentTextColor = mTypedArray.getColor(R.styleable.CustomLetterNavigationView_customTextColorDefault, mContentTextColor);
    mBackgroundColor = mTypedArray.getColor(R.styleable.CustomLetterNavigationView_customBackgroundColorDown, mBackgroundColor);
    mDownContentTextColor = mTypedArray.getColor(R.styleable.CustomLetterNavigationView_customTextColorDown, mDownContentTextColor);
    mContentTextSize = mTypedArray.getDimension(R.styleable.CustomLetterNavigationView_customTextSize, mContentTextSize);
    mContentDiv = mTypedArray.getFloat(R.styleable.CustomLetterNavigationView_customLetterDivHeight, mContentDiv);
    mBackGroundAngle = mTypedArray.getInt(R.styleable.CustomLetterNavigationView_customBackgroundAngle, mBackGroundAngle);
    mTypedArray.recycle();
  }
  
  private int getContentLength() {
    if (mNavigationContent != null) {
      return mNavigationContent.length;
    }
    return 0;
  }
  
  private void scrollCount(float mEventY) {
    //滑动的时候利用滑动距离和每一个字符高度进行取整,获取到Index
    Rect mRect = measureTextSize();
    int index = (int) ((mEventY - getPaddingTop() - getPaddingBottom() - mContentDiv * 2) / (mRect.height() + mContentDiv));
    //防止越界
    if (index >= 0 && index < getContentLength()) {
      String newLetter = mNavigationContent[index];
      //防止重复触发回调
      if (!mCurrentLetter.equals(newLetter)) {
        mCurrentLetter = newLetter;
        if (mOnNavigationScrollerListener != null) {
          mOnNavigationScrollerListener.onScroll(mCurrentLetter, index);
        }
      }
    }
  }
  
  public Rect measureTextSize() {
    Rect mRect = new Rect();
    if (mTextPaint != null) {
      mTextPaint.getTextBounds("田", 0, 1, mRect);
    }
    return mRect;
  }
  
  public void setOnNavigationScrollerListener(OnNavigationScrollerListener onNavigationScrollerListener) {
    this.mOnNavigationScrollerListener = onNavigationScrollerListener;
  }
  
  public void setNavigationContent(String content) {
    if (!TextUtils.isEmpty(content)) {
      mNavigationContent = null;
      mNavigationContent = new String[content.length()];
      for (int i = 0; i < content.length(); i++) {
        mNavigationContent[i] = String.valueOf(content.charAt(i));
      }
    }
    //需要重新测量
    requestLayout();
  }
  public interface OnNavigationScrollerListener {
    //按下
    void onDown();
    //滑动
    void onScroll(String letter, int position);
    //离开
    void onUp();
  }
}

自定义属性


<declare-styleable name="CustomLetterNavigationView">
    <attr name="customTextColorDefault" fORMat="color" />
    <attr name="customTextColorDown" format="color" />
    <attr name="customBackgroundColorDown" format="color" />
    <attr name="customLetterDivHeight" format="dimension" />
    <attr name="customTextSize" format="dimension" />
    <attr name="customBackgroundAngle" format="integer" />
</declare-styleable>
您可能感兴趣的文章:Android程序开发之Fragment实现底部导航栏实例代码Android实现沉浸式通知栏通知栏背景颜色跟随app导航栏背景颜色而改变Android实现底部导航栏功能(选项卡)Android 沉浸式状态栏与隐藏导航栏实例详解Android仿网易客户端顶部导航栏效果超简单的几行代码搞定Android底部导航栏功能Android实现顶部导航栏可点击可滑动效果(仿微信仿豆瓣网)Android仿今日头条顶部导航栏效果的实例代码Android实现简单底部导航栏 Android仿微信滑动切换效果Android项目实战之仿网易顶部导航栏效果


--结束END--

本文标题: Android自定义字母导航栏

本文链接: https://lsjlt.com/news/28440.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Android自定义字母导航栏
    本文实例为大家分享了Android字母导航栏的具体代码,供大家参考,具体内容如下 效果 实现逻辑 明确需求 字母导航栏在实际开发中还是比较多见的,城市选择、名称选择等等可能...
    99+
    2022-06-06
    字母 Android
  • Android自定义View实现字母导航栏
    很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。 ...
    99+
    2022-06-06
    view 字母 Android
  • Android自定义View实现字母导航栏的代码
    思路分析: 1、自定义View实现字母导航栏 2、ListView实现联系人列表 3、字母导航栏滑动事件处理 4、字母导航栏与中间字母的联动 5、字母导航栏与ListView的...
    99+
    2022-06-06
    view 字母 Android
  • Android自定义字母选择侧边栏
    本文实例为大家分享了Android自定义字母选择侧边栏的具体代码,供大家参考,具体内容如下 LetterSideBar.java package com.zb.customvie...
    99+
    2024-04-02
  • Flutter自定义底部导航栏的方法
    本文实例为大家分享了Flutter自定义底部导航栏的具体代码,供大家参考,具体内容如下 文件结构: main.dart import 'package:flutter/materi...
    99+
    2024-04-02
  • bootstrap如何自定义侧边导航栏样式
    这篇文章主要讲解了“bootstrap如何自定义侧边导航栏样式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“bootstrap如何自定义侧边导航栏样式”吧!...
    99+
    2024-04-02
  • 微信小程序如何自定义导航栏
    小编给大家分享一下微信小程序如何自定义导航栏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!CustomNavBar.wxml&l...
    99+
    2024-04-02
  • 微信小程序实现自定义导航栏
    本文实例为大家分享了微信小程序自定义导航栏的具体代码,供大家参考,具体内容如下 1、要实现自定义导航栏,首先得在全局进行相关配置 app.json页面 "window": {    ...
    99+
    2024-04-02
  • 微信小程序自定义导航栏效果
    本文实例为大家分享了微信小程序自定义导航栏的具体代码,供大家参考,具体内容如下 第一步 添加属性 “navigationStyle”: “cust...
    99+
    2024-04-02
  • Android自定义ViewPagerIndicator实现炫酷导航栏指示器(ViewPager+Fragment)
    ViewPagerIndicator导航栏指示器运行效果: 实现这个效果,我是看了很多大神写的博客和视频后自己敲的,欢迎指正 github地址:https://github....
    99+
    2022-06-06
    fragment Android
  • Android design包自定义tablayout的底部导航栏的实现方法
    以前做项目大多用的radiobutton,今天用tablayout来做一个tab切换页面的的效果. 实现的效果就是类似QQ.微信的页面间(也就是Fragment间)的切换.如图...
    99+
    2022-06-06
    方法 tablayout Android
  • 微信小程序中怎么自定义导航栏
    本篇文章给大家分享的是有关微信小程序中怎么自定义导航栏,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。step1 自定义第一步 取得导航栏的控制...
    99+
    2024-04-02
  • uniapp微信小程序怎么自定义导航栏
    本篇内容介绍了“uniapp微信小程序怎么自定义导航栏”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!首先我们在自定义导航栏的时候,我们需要知...
    99+
    2023-07-02
  • Android怎么实现字母导航控件
    这篇文章主要介绍“Android怎么实现字母导航控件”,在日常操作中,相信很多人在Android怎么实现字母导航控件问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Android怎么实现字母导航控件”的疑惑有所...
    99+
    2023-06-26
  • SwiftUI怎么自定义导航
    这篇文章主要介绍“SwiftUI怎么自定义导航”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“SwiftUI怎么自定义导航”文章能帮助大家解决问题。前言默认情况下,SwiftUI提供的各种导航API在...
    99+
    2023-06-30
  • 微信小程序怎么实现自定义导航栏
    今天小编给大家分享一下微信小程序怎么实现自定义导航栏的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、要实现自定义导航栏,首...
    99+
    2023-06-29
  • 示例演示uniapp如何实现自定义导航栏
    随着移动端应用的发展,导航栏成为了许多应用必备的功能之一。而Uni-app是一款可以同时开发多个移动端应用(包括iOS、Android等)的全栈式框架,它提供了丰富的组件以及API,方便开发者快速复用和定制应用功能。在Uni-app中,要实...
    99+
    2023-05-14
  • 微信小程序自定义底部导航栏组件
    本文实例为大家分享了微信小程序底部导航栏组件的具体实现代码,供大家参考,具体内容如下 1、在自己项目的公共组件的文件价下新建tabbar.vue(定义的自定义导航栏组件) <...
    99+
    2024-04-02
  • Vue自定义部分页面显示导航栏功能
    目录遇到的问题:解决方法:遇到的问题: 最近在用Vue+elementUI开发一个网站的前端,网站的逻辑是没有账号的用户先注册,有账号的用户直接登录,登录后才能进入网站的主页。在设计...
    99+
    2024-04-02
  • Android仿微信实现首字母导航条
    本文介绍Android实现首字母导航条,先看张效果图,具体怎么实现看代码吧 具体的步骤 1.整体布局的显示 2. 实现A-Z的分组 3. 自定义A-Z的导航条 4. 中...
    99+
    2022-06-06
    导航条 字母 Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作