最近的项目需要一个类似联系人的列表,包括模糊的查询、拼音首字母从a到z的分组排序以及收藏功能。 虽然参考了网上的例子,但是我觉得还是自己操作小刀实现了所有的功能。 今天先实现联系方式右侧的边栏【A~Z】。 上图:
右边是从a到z的侧面菜单导航栏。 单击右侧的侧面菜单导航栏,可以看到当前正在中央单击item。 我相信这个UI是大家熟知的。 很多APP都有这样的接口。 最典型的是通讯录。
按照以下步骤创建名为SiderBarMenu的新类,继承View并自定义View。 首先,实现它的三种构建方法。 如下所示。
公共信息数据库(上下文上下文)。
{
this (上下文、空值);
}
publicsidebarmenu (上下文上下文,属性et attrs ) )。
{
this (上下文,attrs,0 );
}
publicsidebarmenu (上下文上下文,属性et attrs,int style ) )。
{
super (上下文、attrs、style );
init (;
}
私有语音init (
{
mSideBarMenuPaint=new Paint (;
//设定画笔颜色
msidebarmenupaint.setcolor (color.red;
//设定字体大小
msidebarmenupaint.settext size (30;
//设置字体
msidebarmenupaint.set typeface (typeface.default _ bold;
}
在三个构造方法中定义初始化方法,然后初始化稍后使用的变量等。 在此处,您可以初始化绘画(画笔)的实例,并设置画笔的颜色、字体大小和字体。 在此之前,定义所需的变量。
//刷子
隐私绘制msidebarmenupaint;
//定义用户并单击item标记
私密int click=-1;
//侧面导航栏中的字符
private String[] SIDEBAR={'A '、' b '、' c '、' d '、' e '、' f '、' g '、' h '、' I ',
包括: j、k、l、m、n、o、p、q、s、t、u、v,
' w '、' x '、' y '、' Z'};
显示tips控件
隐私文本视图MTV tips;
这些结束后,开始画边栏的菜单。 首先,将View的onDraw ()方法重写为:
@Override
protectedvoidondraw (canvas canvas ) )。
{
super.Ondraw(Canvas );
//获取在布局文件中设置的控件的宽度、高度: layout_width和layout_height两个值;
int width=getWidth (;
int height=getHeight (;
每Item的高度
intsidebaritemheight=height/sidebar.length;
for(intI=0; i SIDEBAR.length; I )
{
//计算我们绘制的文字的x坐标,计算公式:控件宽度/2-文字宽度/2目的:文字的水平中心
float xpos=width/2-msidebarmenupaint.measure text (sidebar [ I ] )/2;
//计算我们绘制文字的y坐标,计算公式:控件高度*当前项数控件高度/2目的:文字垂直居中
float ypos=sidebaritemheight * isidebaritemheight/2;
//绘制侧面导航栏
canvas.drawtext(sidebar[I],xPos,yPos,mSideBarMenuPaint );
//重置画笔。 重置画笔时,必须重置画笔属性
//mSideBarMenuPaint.reset (;
}
}
首先,获取布局文件的宽度、高度。 然后计算出各item的高度。 然后,计算各item的x、y
坐标。之后调用canvas.drawText()方法绘制我们的侧边栏,这儿我注释了一个reset()方法,如果调用它我们就需要每次在循环里面重新设置paint的属性,因为前面我在init()方法中设置过,所以我把这个方法注释掉了。而且考虑到后面也没有拿这个画笔做其他操作。这时候我们运行程序应该可以到侧边栏已经绘制成功了。接下来就是处理触摸事件了。我们需要重写dispatchTouchEvent()方法。来手动处理触摸事件。
/** * 手动处理触摸事件 * *@param event *@return */
@Override
public boolean dispatchTouchEvent(MotionEvent event)
{
//获取触摸事件:ACTION_DOWN、ACTION_MOVE、ACTION_UP
int action = event.getAction();
//获取触摸的Y坐标
float yPos = event.getY();
//判断点击的是那一个item。计算公式:触摸的Y坐标/控件高度*侧边导航栏item总数。
int pos = (int) (yPos / getHeight() * SIDEBAR.length);
//记录之前用户点击的item
int oldClick = click;
//处理触摸事件,up事件单独处理,其他(ACTION_DOWN、ACTION_MOVE)在default中去处理。
switch (action)
{
case MotionEvent.ACTION_UP:
//复位
click = -1;
if (mTvTips != null)
{
mTvTips.setVisibility(View.GONE);
}
invalidate();
break;
default:
if (oldClick != pos)
{
if (pos > 0 && pos < SIDEBAR.length)
{
if (mTvTips != null)
{
mTvTips.setText(SIDEBAR[pos]);
mTvTips.setVisibility(View.VISIBLE);
}
click = pos;
//通知View树重绘,主线程用:invalidate(),非主线程用:postInvalidate();
invalidate();
}
}
break;
}
return true;
}
这儿代码稍稍长一点,我从上到下给解释下,首先我们要通过event.getAction()方法拿到用户的触摸事件,之后在通过event.getY()方法获取用户触摸的Y坐标。拿到Y坐标之后,我们就可以判断用户当前触摸的哪一个item。计算公式:触摸的Y坐标/控件高度*侧边导航栏item总数。不知道大家能理解到这个公式不,理解不到自己用本子算吧。或者找个六年纪一下的同学帮你算。哈哈!然后定义一个变量oldClick来保存用户之前点击的位置。
完成上面的操作之后,我们就开始判断用户的触摸事件了,这儿我们将ACTION_UP事件单独处理,因为ACTION_DOWN、ACTION_MOVE的处理逻辑一样,所以我放到了default里面,
ACTION_UP:
我们需要处理当用户抬手之后隐藏TextView并且将click恢复默认值,不然dmdgtx重复点击同一个item是没有效果的。
ACTION_DOWN&ACTION_MOVE:
首先判断之前点击的item位置和现在的位置是否一样,如果不一样,再判断当前位置是否越界,之后设置要显示的内容并且将TextView设置为可见,之后将当前位置重新赋值,并且通知View树重绘。
最后我们再向外抛一个设置TextView的方法。
public void setTextView(TextView tips)
{
this.mTvTips = tips;
}
现在在我们布局文件中使用:
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="right">
android:id="@+id/sbm_siderbarmenu"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"/>
android:id="@+id/tv_tips"
android:layout_width="50dp"
android:layout_height="50dp"
android:visibility="gone"
android:layout_centerInParent="true"
android:background="@drawable/shape_tips_bg"
android:gravity="center"
android:text="H"
android:textColor="#fff"/>
最后在MainActivity中使用:
public class MainActivity extends AppCompatActivity {
private SideBarMenu mSiderBarMenu;
private TextView mTvTips;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//setClickListener();
}
private void initView()
{
mSiderBarMenu = (SideBarMenu) findViewById(R.id.sbm_siderbarmenu);
mTvTips = (TextView) findViewById(R.id.tv_tips);
mSiderBarMenu.setTextView(mTvTips);
}
}