1. 程式人生 > >Android控制元件--側邊欄SideBar

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);
    }
}

以上就是全部程式碼了。希望自己能多多練習更加熟練的掌握。