由于项目原因,需要一个类似联系人列表那种选择的“导航”,这玩意叫什么名, 我至今还是不太清楚, 听群里有哥们说this is sidebar, 那咱们也叫他sidebar吧。首先来一张图片, 来看看sidebar到底是个什么玩意。

ok, 就这玩意, 大家应该很熟悉吧, 这篇博客我们就来做这么一个东西,首先说明一点:代码~ so easy。

首先,来分析一下,当我们看到这个效果后,应该怎么去思考吧。第一眼看去,这玩意并不能实现,只要extends view, 然后measure,然后draw就可以。再看第二眼,应该去思考,如何判断当前滑动点对应的文字。ok, 为了提高灵活性,我们还需要把文字颜色、行间距、文本列表内容提取出来,让使用者可以在xml中配置使用。

1、编写attrs.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="KeyPad"><attr name="color" format="color|reference" /><attr name="padding" format="dimension|reference" /><attr name="android:textSize" /><attr name="android:entries" /></declare-styleable>
</resources>

color代表了字体的颜色,padding代表着行间距,android:textSize代码文字大小,android:entries代表列表内容,这里面需要注意的就是后两个以android:开头的,表示,直接使用android本身提供好的。

2、创建KeyPad.java文件

这里的KeyPad就是我们的SideBar啦, 刚开始写的时候不知道这玩意叫什么名,so...

public class KeyPad extends View {private String[] mKeys = { "#", "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" };private TextPaint mTextPaint;private Rect mTextBounds[];private float mPadding;private String mSelected;private OnKeySelectedListener mListener;...public void setEntries(String[] entries) {if (entries == null || entries.length == 0) return;mKeys = entries;mTextBounds = new Rect[mKeys.length];requestLayout();invalidate();}public void setOnKeySelectedListener(OnKeySelectedListener l) {mListener = l;}public interface OnKeySelectedListener {public void onSelected(String key);public void onDown();public void onUp();}
}

mKeys就是我们需要显示的列表,mSelected代表当前选中的文本,最后还有一个OnKeySelectedListener,有三个方法,onSelected表示有文本选中时,onDown和onUp表示按下和抬起时。KeyPad的基本框架就是这样,接下来的内容就是重写view那些步骤了, 获取属性、测量、绘制。。。

3、获取属性值

在第一步中,我们提供了几个属性,这几个属性可以在xml中进行配置,然后我们的KeyPad在构造方法中进行获取,来看看获取的代码。

public KeyPad(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.KeyPad, defStyle, 0);mPadding = ta.getDimension(R.styleable.KeyPad_padding, 20.f);int color = ta.getColor(R.styleable.KeyPad_color, Color.BLUE);float defaultTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 15, getResources().getDisplayMetrics());float textSize = ta.getDimension(R.styleable.KeyPad_android_textSize, defaultTextSize);if (ta.hasValue(R.styleable.KeyPad_android_entries)) {mKeys = context.getResources().getStringArray(ta.getResourceId(R.styleable.KeyPad_android_entries, 0));}ta.recycle();...
}

这里仅仅需要注意的就是那个if语句,我们需要判断使用者是否在xml中通过android:entries="@array/xxx"配置了内容,如果配置了,则去获取它, 否则,使用默认。

4、view的测量

在KeyPad中,高度是最重要的,我们需要精确的测量KeyPad的高度,包括所有文本的高度和以及文本的行间距。上代码:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int width = 0;int height = 0;int length = mKeys.length;for (int i = 0; i < length; i++) {mTextBounds[i] = new Rect();mTextPaint.getTextBounds(mKeys[i], 0, mKeys[i].length(), mTextBounds[i]);width = Math.max(width, mTextBounds[i].width());height += mTextBounds[i].height() + mPadding;}height -= mPadding;width += getPaddingRight() + getPaddingLeft();height += getPaddingTop() + getPaddingBottom();setMeasuredDimension(width + 10, height);
}

我们去遍历所有的文本,在循环中顺便初始化保存每个文本宽高信息的Rect,然后通过mTextPaint.getTextBounds去获取需要的东西,接下来的Math.max,能保证,我们的KeyPad的宽度是所有文本中最宽的那个的宽度,height就是一个累加的过程。纵观代码,这个view的测量还是很容易的。最后通过setMeasuredDimension保存一下测量值。

5、文本内容的绘制

KeyPad的大小我们已经测量完毕了,那么接下来的任务就是去绘制内容了, KeyPad的绘制部分也很容易。

@Overrideprotected void onDraw(Canvas canvas) {int length = mKeys.length;int center = getMeasuredWidth() / 2;int height = 0;for (int i = 0; i < length; i++) {height += mTextBounds[i].height();canvas.drawText(mKeys[i], center - mTextBounds[i].width() / 2+ getPaddingLeft(), height, mTextPaint);height += mPadding;}}

不多说了, 就是一行行的去绘制内容,注意,我们绘制的内容在水平方向上都是居中的。

6、重点:获取当前touch的内容

我们如何知道,当前touch的点对应哪一块内容呢? 我的思路是:获取当前touch的y坐标, 然后遍历每个文本的位置,进行比对,如果当前touch的y左边在某个文本坐标的区域内,则表示,touch到了该内容。先来看看代码是怎么实现的吧。

@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_UP) {mSelected = null;if (mListener != null) mListener.onUp();return true;}if (event.getAction() == MotionEvent.ACTION_DOWN) {if (mListener != null) mListener.onDown();}int y = (int) event.getY();int length = mKeys.length;int height = getPaddingTop();for (int i = 0; i < length; i++) {if (y >= height && y <= height + mTextBounds[i].height() + mPadding) {if (mKeys[i].equals(mSelected)) break;mSelected = mKeys[i];if (mListener != null) mListener.onSelected(mSelected);break;}height += mTextBounds[i].height() + mPadding;}return true;}

我们选择重写dispatchTouchEvent来处理touch。

首先来看看两个if语句,第一个if语句是判断如果是抬起的时候,这个时候,我们清空保存的选择项,并且回调onUp()以便使用者在抬起的时候做点什么。

第二个if语句是按下的时候,这里很简单, 只是单纯的回调了onDown()。

下面的代码是重点:

int y = (int) event.getY();int length = mKeys.length;int height = getPaddingTop();for (int i = 0; i < length; i++) {if (y >= height && y <= height + mTextBounds[i].height() + mPadding) {if (mKeys[i].equals(mSelected)) break;mSelected = mKeys[i];if (mListener != null) mListener.onSelected(mSelected);break;}height += mTextBounds[i].height() + mPadding;}

首先获取到当前触摸的y坐标,然后,第4行,一个for循环,我们去遍历所有的内容,用一个if语句去判断当前触摸的点是否在这个内容所在的区域内,如果在,还有一个判断,if(mKey[i].equals(mSelected)) break主要是防止多次回调同一个内容,接下来,保存当前touch的内容并回调。

重点我们来看看if的条件是怎么判断的。

if (y >= height && y <= height + mTextBounds[i].height() + mPadding)  -- height保存的是一个累加的高度,所以第一个条件很容易理解了,第二个条件是当y小于当前累加高度+当前文本的高度时。这个if的意思也就是“当y的位置在height和height+当前内容高度之间”。 下面我们来画图说明一下:

7、开始布局xml文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="org.loader.keypad.MainActivity" ><TextViewandroid:id="@+id/tv_key"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:background="#AA888888"android:padding="50dp"android:textColor="@android:color/white"android:visibility="gone" /><org.loader.keypad.KeyPadxmlns:pad="http://schemas.android.com/apk/res/org.loader.keypad"android:id="@+id/kp_keys"android:background="@android:color/darker_gray"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_marginRight="5dp"android:layout_marginTop="30dp"android:textSize="15sp"android:entries="@array/keys"pad:padding="10dp"pad:color="#FF0000FF" /></RelativeLayout>

一个TextView, 用来显示当我们选中时的那个文本,重点来看看KeyPad的配置。 android:textSize="15sp"指定文本的大小,android:entries="@array/keys"指定数据集(就是一个string-array),pad:padding="10dp"指定文本的大小,pad:color="#FF0000FF"指定文本的颜色。

8、在Activity获取touch的内容并显示

public class MainActivity extends Activity {private TextView mKeyTextView;private KeyPad mKeyPad;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mKeyTextView = (TextView) findViewById(R.id.tv_key);mKeyPad = (KeyPad) findViewById(R.id.kp_keys);mKeyPad.setOnKeySelectedListener(new OnKeySelectedListener() {@Overridepublic void onSelected(String key) {mKeyTextView.setText(key);}@Overridepublic void onDown() {mKeyTextView.setVisibility(View.VISIBLE);                }@Overridepublic void onUp() {mKeyTextView.setVisibility(View.GONE);}});//        mKeyPad.setEntries(new String[] {"aaa","bbb"});}
}

主要看看设置的Listener里面,在onDown的时候我们让TextView显示出来, 在onUp我们又让TextView隐藏起来,在onSelected中控制TextView显示的内容。

最后,我们来看看整体效果

自己动手做sidebar相关推荐

  1. 开关面板如何自己印字_如何自己动手做一个智能开关

    现在的智能家居这么火,对于想自己动手的小伙伴们来说,都想自己去做一些家里使用 的智设备.现在的中国不缺卖唱卖惨的,缺的是能动手创造一些能实际使用的而不是哗众取宠的人,天天喊着要反击外国技术封锁.那么我 ...

  2. proteus仿真micropython_【雕爷学编程】MicroPython动手做(04)——零基础学MaixPy之尝试运行...

    1.hello micropython #MicroPython动手做(04)--零基础学MaixPy之基本示例 #程序之一:hellomicropython #MicroPython动手做(04)- ...

  3. 不使用物理引擎,自己动手做真实物理的模拟投篮游戏

    最近打算做一个2D投篮游戏,由于对于BOX2D等物理引擎并不熟悉,加之一开始低估了游戏所需要的碰撞检测复杂度,认为仅仅涉及4面墙,篮球,篮板,篮筐,篮网的碰撞检测并不复杂.因此决定自己实现所需要的碰撞 ...

  4. python合成语音_MicroPython动手做(25)——语音合成与语音识别

    6.AB按键切换语言合成项目 [mw_shl_code=python,true]#MicroPython动手做(25)--语音合成与语音识别 #AB按键切换语言合成项目 from mpython im ...

  5. arduino 土壤温湿度传感器_【雕爷学编程】Arduino动手做(70)---土壤湿度传感器...

    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的.鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为 ...

  6. 《自己动手做交互系统》——第2章 音乐蛋糕盘

    本节书摘来异步社区<自己动手做交互系统>一书中的第2章,作者:徐皓祎,更多章节内容可以访问云栖社区"异步社区"公众号查看 第2章 音乐蛋糕盘 自己动手做交互系统 第2章 ...

  7. 「雕爷学编程」Arduino动手做(38)——joystick双轴摇杆模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  8. 「雕爷学编程」Arduino动手做(36)——WS2812B 4位彩灯模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  9. 「雕爷学编程」Arduino动手做(35)——模拟量声音传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

最新文章

  1. 工具安装===Sublime Text-安装
  2. Android系统启动过程全解析
  3. 多路复用IO模型中的select和epoll
  4. php oci 11g.dll下载,Oracle oci.dll
  5. Python学习笔记(十)—— 高级特性
  6. 华为Mate 30 Pro全新配色曝光:“赤茶橘”颜值超高
  7. web前端是什么?如何能成为一名合格的前端开发工程师?
  8. 哪个计算机无法做到双屏显示,[工具/ PC]如何在计算机上实现双屏显示?
  9. 机器学习算法一:K-近邻算法
  10. nova组件-launch,shut off,start,lock,reboot,terminate虚拟机
  11. 购物提醒(基于python的信息轰炸)
  12. 记一次千人大项目的感受
  13. 图片自动适应表格的大小
  14. server取出多个最小值 sql_sql-server
  15. 键盘上F1~F12各个功能键的作用
  16. Resistors in Parallel(Gym - 102028E 2018 ICPC 焦作E题 大数+规律C++版)
  17. java web权限管理
  18. 阿里又一员猛将出走江湖?原钉钉CEO“无招”将离职创业,新公司被投资方疯抢!阿里辟谣:人还没走!...
  19. 本质安全设备标准(IEC60079-11)的理解(二)
  20. H5调用本地摄像头拍摄照片

热门文章

  1. 五、Hystrix断路器
  2. Extrinsic Calibration of a Camera and Laser Range Finder (improves camera calibration)阅读笔记
  3. 高效学习方法论 学习笔记
  4. 基于GINA/凭证提供程序的自助密码管理
  5. windows7浏览器无法打开html,Win7系统chrome浏览器无法打开怎么回事?Win7系统chrome浏览器无法打开的解决方法...
  6. ggg的区别+linux、GNU、GNU/linux
  7. python第一弹 爬虫淘女郎图片
  8. 会议平板红外和电容触控区别,哪个好?
  9. virtual audio cable 虚拟声卡
  10. 2010/12/19英语单词背诵