Android控件--侧边栏SideBar

说明
很多应用中我们都能看到关于侧边栏的使用,比如微信啊,QQ啊,美团啊等等,最常见的应该就是通讯录里面对联系人进行A~Z的排序。侧边栏主要是方便用户进行字母索引。资料链接:http://blog.csdn.net/xiaanming/article/details/12684155
今天实现的控件效果如下图所示:
这里写图片描述

工程结构图:
这里写图片描述

1.Sidebar的JAVA类文件

package com.example.mysidebar;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import org.w3c.dom.Attr;

/**
 * Created by Administrator on 2016/7/7 0007.
 */
public class SideBar extends View {
    public SideBar(Context context) {
        super(context);
    }

    public SideBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    /**
     * 触摸字母索引发生变化的回调接口
     */
    private onLetterTouchedChangeListener onLetterTouchedChangeListener = null;
    //侧边栏字母显示
    private String[] alphabet = {
            "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", "#"
    };
    //变量 currentChoosenAlphabetIndex 用来标示当前手指触摸的字母索引在 alphabet 数组中的下标
    private int currentChoosenAlphabetIndex = -1;
    //定义画笔
    private Paint paint = new Paint();
    //当手指在 SideBar 上滑动的时候,会有一个 TextView 来显示当前手指触摸的字母索引,所以还需要一个属性
    private TextView textViewDialog = null;

    /**
     * 为SideBar设置显示字母的TextView
     * @param textViewDialog
     */
    public void setTextViewDialog(TextView textViewDialog) {
        this.textViewDialog = textViewDialog;
    }

    /**
     * 绘制列表控件的方法
     * 将要绘制的字母以从上到下的顺序绘制在一个指定区域
     * 如果是进行选中的字母就进行高亮显示
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取SideBar的高度
        int viewHeight = getHeight();
        //获取SideBar的宽度
        int viewWidth = getWidth();
        //获得每个字母索引的高度
        int singleHeight = viewHeight / alphabet.length;

        //绘制每一个字母的索引
        for (int i = 0; i < alphabet.length; i++) {
            paint.setColor(Color.rgb(34, 66, 99));//设置字母颜色
            paint.setTypeface(Typeface.DEFAULT_BOLD);//设置字体
            paint.setTextSize(20);//设置字体大小
            paint.setAntiAlias(true);//抗锯齿

            //如果当前的手指触摸索引和字母索引相同,那么字体颜色进行区分
            if (currentChoosenAlphabetIndex == i) {
                paint.setColor(Color.parseColor("#3399ff"));
                paint.setFakeBoldText(true);
            }

            /*
         * 绘制字体,需要制定绘制的x、y轴坐标
         *
         * x轴坐标 = 控件宽度的一半 - 字体宽度的一半
         * y轴坐标 = singleHeight * i + singleHeight
         */

            float xpos = viewWidth / 2 - paint.measureText(alphabet[i]) / 2;
            float ypos = singleHeight * i + singleHeight;
            canvas.drawText(alphabet[i], xpos, ypos, paint);

            // 重置画笔,准备绘制下一个字母索引
            paint.reset();
        }
    }

    public void setOnLetterTouchedChangeListener(
            onLetterTouchedChangeListener onLetterTouchedChangeListener) {

        this.onLetterTouchedChangeListener = onLetterTouchedChangeListener;
    }

    private onLetterTouchedChangeListener getOnLetterTouchedChangeListener() {
        return onLetterTouchedChangeListener;
    }

    /**
     * 当手指触摸的字母索引发生变化时,调用该回调接口
     *
     * @author owen
     */
    public interface onLetterTouchedChangeListener {
        public void onTouchedLetterChange(String letterTouched);
    }


    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        // 触摸事件的代码
        final int action = event.getAction();
        //手指触摸点在屏幕的Y坐标
        final float touchYPos = event.getY();
        // 因为currentChoosenAlphabetIndex会不断发生变化,所以用一个变量存储起来
        int preChoosenAlphabetIndex = currentChoosenAlphabetIndex;
        final onLetterTouchedChangeListener listener = getOnLetterTouchedChangeListener();

        // 比例 = 手指触摸点在屏幕的y轴坐标 / SideBar的高度
        // 触摸点的索引 = 比例 * 字母索引数组的长度
        final int currentTouchIndex = (int) (touchYPos / getHeight() * alphabet.length);

        switch (action) {
            case MotionEvent.ACTION_UP:
                // 如果手指没有触摸屏幕,SideBar的背景颜色为默认,索引字母提示控件不可见
                setBackground(new ColorDrawable(0x00000000));
                currentChoosenAlphabetIndex = -1;
                invalidate();
                if (textViewDialog != null) {
                    textViewDialog.setVisibility(View.INVISIBLE);
                }
                break;
            default:
                // 其他情况,比如滑动屏幕、点击屏幕等等,SideBar会改变背景颜色,索引字母提示控件可见,同时需要设置内容
                setBackgroundResource(R.drawable.sidebar_background);

                // 不是同一个字母索引
                if (currentTouchIndex != preChoosenAlphabetIndex) {
                    // 如果触摸点没有超出控件范围
                    if (currentTouchIndex >= 0 && currentTouchIndex < alphabet.length) {
                        if (listener != null) {
                            listener.onTouchedLetterChange(alphabet[currentTouchIndex]);
                        }

                        if (textViewDialog != null) {
                            textViewDialog.setText(alphabet[currentTouchIndex]);
                            textViewDialog.setVisibility(View.VISIBLE);
                        }

                        currentChoosenAlphabetIndex = currentTouchIndex;
                        invalidate();
                    }
                }
                break;
        }

        return super.dispatchTouchEvent(event);
    }
}

SideBar类就是ListView右侧的字母索引View,我们需要使用setTextView(TextView textViewDialog)来设置用来显示当前按下的字母的TextView,以及使用setOnLetterTouchedChangeListener方法来设置回调接口,在回调方法onLetterTouchedChangeListener(String s)中来处理不同的操作

2.引用SideBar的XML文件(activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.mysidebar.MainActivity">

    <TextView
        android:id="@+id/textViewDialog"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_centerInParent="true"
        android:background="#3399ff"
        android:gravity="center"
        android:padding="10dp"
        android:text="1"
        android:textColor="@android:color/white"
        android:textSize="50dp"
        android:textStyle="bold"
        android:visibility="invisible" >
    </TextView>

    <com.example.mysidebar.SideBar
        android:id="@+id/sideBar"
        android:layout_width="25dp"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true" />
</RelativeLayout>

背景自定义

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient 
    android:startColor="#99C60000" 
    android:endColor="#99C60000" 
    android:angle="90.0" />

    <corners
        android:topLeftRadius="8dip"
        android:bottomLeftRadius="8dip"/>

</shape>

shape是用来定义形状的,gradient定义该形状里面为渐变色填充,startColor起始颜色,endColor结束颜色,angle表示方向角度。当angle=0时,渐变色是从左向右。 然后逆时针方向转,当angle=90时为从下往上
corner是用来定义圆角的,radius为角的弧度,值越大角越圆。
我们还可以把四个角设定成不同的角度,

同时设置五个属性,则Radius属性无效

android:Radius=”20dp” 设置四个角的半径

android:topLeftRadius=”20dp” 设置左上角的半径
android:topRightRadius=”20dp” 设置右上角的半径
android:bottomLeftRadius=”20dp” 设置右下角的半径
android:bottomRightRadius=”20dp” 设置左下角的半径

3.MainActivity的JAVA类文件

package com.example.mysidebar;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private SideBar indexBar;
    /** 
     * 显示字母的TextView 
     */  
    private TextView textViewDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        indexBar = (SideBar) findViewById(R.id.sideBar);
        textViewDialog = (TextView) findViewById(R.id.textViewDialog);
        indexBar.setTextViewDialog(textViewDialog);
    }
}

以上就是全部代码了。希望自己能多多练习更加熟练的掌握。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值