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);
}
}
以上就是全部程式碼了。希望自己能多多練習更加熟練的掌握。