您的位置:首页 > 移动开发 > Android开发

android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色

2015-12-18 11:35 901 查看
android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色。

由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如android的自带的TextView强大,只是继承于view,而不是textview。

主要用途:电话本的侧边快速导航等

效果图:(自定义字符串 “#ABCDEFGHIJKLMN),可以实现自定义任意字符串



view的实现:

package cn.carbs.verticalstraighttextview.view;

import cn.carbs.verticalstraighttextview.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
/**
* 参考资料:
*         http://chris.banes.me/2014/03/27/measuring-text/ *         http://blog.163.com/gobby_1110/blog/static/2928171520136304172378/ * @author Rick.Wang
*
*/
public class VerticalStraightTextView extends View {

private final static int DEFAULT_TEXT_SIZE = 15;
private final static int DEFAULT_TEXT_COLOR = 0xFF000000;
private final static int DEFAULT_TEXT_COLOR_PICKED = 0xFF990000;
private final static int DEFAULT_CHAR_SPACE = 0;

private TextPaint mTextPaint;
private TextPaint mTextPaintPicked;
private String mText = "";

private int mTextLength = 0;
private int mCharGap = 0;
private int mCharWidth = 0;
private int mCharHeight = 0;

private int currPickedCharIndex = -1;

float[] coordinates = null;

public float[] getCoordinates(){
return coordinates;
}

public VerticalStraightTextView(Context context) {
super(context);
init();
}

public VerticalStraightTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.verticalstraighttextview);

int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.verticalstraighttextview_text:
mText = a.getString(attr);
if(mText == null){
mText = "";
break;
}
mTextLength = mText.length();
break;
case R.styleable.verticalstraighttextview_textSize:
int textSize = a.getDimensionPixelOffset(R.styleable.verticalstraighttextview_textSize, DEFAULT_TEXT_SIZE);
if (textSize > 0) {
mTextPaint.setTextSize(textSize);
mTextPaintPicked.setTextSize(textSize);
}
break;

case R.styleable.verticalstraighttextview_charGap:
mCharGap = a.getDimensionPixelSize(R.styleable.verticalstraighttextview_charGap, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, DEFAULT_CHAR_SPACE, getResources().getDisplayMetrics()));
break;
case R.styleable.verticalstraighttextview_textColor:
mTextPaint.setColor(a.getColor(R.styleable.verticalstraighttextview_textColor, DEFAULT_TEXT_COLOR));
break;
case R.styleable.verticalstraighttextview_textColorPicked:
mTextPaintPicked.setColor(a.getColor(R.styleable.verticalstraighttextview_textColorPicked, DEFAULT_TEXT_COLOR_PICKED));
break;
}
}
a.recycle();

requestLayout();
invalidate();
}

private final void init() {
mTextPaint = new TextPaint();
mTextPaint.setAntiAlias(true);
mTextPaint.setTextSize(DEFAULT_TEXT_SIZE);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaintPicked = new TextPaint(mTextPaint);
mTextPaint.setColor(DEFAULT_TEXT_COLOR);
mTextPaintPicked.setColor(DEFAULT_TEXT_COLOR_PICKED);
}

public void setText(String text) {
if(text == null){
text = "";
}
if(!mText.equals(text)){
mText = text;
mTextLength = text.length();
requestLayout();
invalidate();
}
}

public void setTextSize(int size) {
if(mTextPaint.getTextSize() != size){
mTextPaint.setTextSize(size);
mTextPaintPicked.setTextSize(size);
requestLayout();
invalidate();
}
}

public void setTextColor(int color) {
if(color != mTextPaint.getColor()){
mTextPaint.setColor(color);
invalidate();
}
}

public void setTextColorPicked(int color) {
if(color != mTextPaintPicked.getColor()){
mTextPaintPicked.setColor(color);
invalidate();
}
}

public int getCharHeight(){
return mCharGap + mCharHeight;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d("1218", "onMeasure");
//获取字体宽度
float maxCharWidth = 0f;
for(int i = 0; i < mTextLength; i++){
maxCharWidth = Math.max(mTextPaint.measureText(mText.substring(i, i+1)), maxCharWidth);
}
mCharWidth = (int)Math.ceil(maxCharWidth);

//获取字体高度
Rect textBounds = new Rect();
mTextPaint.getTextBounds(mText, 0, mTextLength, textBounds);
mCharHeight = textBounds.height();

setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}

private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = this.getPaddingLeft() + this.getPaddingRight() + mCharWidth;
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}

private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = getPaddingTop() + getPaddingBottom();
if(mTextLength > 0){
result += mTextLength * (mCharGap + mCharHeight) - mCharGap;
}
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);
}
}
return result;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d("1218", "onDraw");
if(mTextLength == 0){
return;
}

int height = getMeasuredHeight();
int measuredWidth = getMeasuredWidth();

int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();

//默认居中
int x = paddingLeft + (measuredWidth - paddingLeft - paddingRight)/2;
int y = 0;

int cellHeight = (height - paddingTop - paddingBottom)/ mTextLength;
//TODO 可能会有bug
if(coordinates == null || coordinates.length != mTextLength){
coordinates = new float[mTextLength + 1];
}
coordinates[0] = 0;
for(int i = 0; i < mTextLength; i++){
y = paddingTop + i * cellHeight + cellHeight/2;
coordinates[i + 1] = y + cellHeight/2;
if(currPickedCharIndex != i){
canvas.drawText(mText, i, i + 1, x, y, mTextPaint);
}else{
canvas.drawText(mText, i, i + 1, x, y, mTextPaintPicked);
}
}
coordinates[mTextLength] = height;
}

//y is the coordinate-Y
//this function can return the "touched char"
public int getPickedCharIndex(float[] coordinates, float y){
int start = 0;
int end = coordinates.length - 1;
while (start != end - 1) {
int middle = (start + end) / 2;
if (y < coordinates[middle]) {
end = middle;
} else if (y > coordinates[middle]) {
start = middle;
}
}
return start;
}

/***************************************
*
*         +---------------+  <-- Y == coordinates[0]
*         |        #        |
*         |---------------|            coordinates[1]
*         |        A        |
*         |---------------|            coordinates[2]
*         |        B        |
*         |---------------|            coordinates[3]
*         |        C        |
*         +---------------|            coordinates[4]
***************************************/

public int getPickedCharIndex(float y){
//优化查询
//如果当前的>-1,说明正在touchEvent
if(currPickedCharIndex > -1){
if(coordinates[currPickedCharIndex] < y && y < coordinates[currPickedCharIndex+1]){
return currPickedCharIndex;
}
}

int start = 0;
int end = coordinates.length - 1;
while (start != end - 1) {
int middle = (start + end) / 2;
if (y < coordinates[middle]) {
end = middle;
} else if (y > coordinates[middle]) {
start = middle;
}
}
return start;
}

public void setCurrPickedCharIndex(int index){
if(currPickedCharIndex != index){
currPickedCharIndex = index;
invalidate();
}
}

}


style文件的定义:(将此代码写入values文件夹下的styles.xml文件中)

<declare-styleable name="verticalstraighttextview">
<attr name= "text" format ="string" />
<attr name= "textColor" format ="reference|color" />
<attr name= "textColorPicked" format="reference|color" />
<attr name= "textSize" format="reference|dimension" />
<attr name= "charGap" format ="reference|dimension" />
</declare-styleable >


布局文件引入此自定义view:

<cn.carbs.verticalstraighttextview.view.VerticalStraightTextView
android:id="@+id/kk"
android:layout_width="wrap_content"
android:padding="5dp"
android:layout_height="fill_parent"
android:background="#33333333"
app:textSize="20sp"
app:text= "#ABCEDFGHIJKLMN" />


在activity中的使用:

verticalView = (VerticalStraightTextView)this.findViewById(R.id.kk);

verticalView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "onclick", Toast.LENGTH_SHORT).show();
}
});

verticalView.setOnTouchListener(new View.OnTouchListener() {

@Override
public boolean onTouch(View view, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN:
verticalView.setCurrPickedCharIndex(verticalView.getPickedCharIndex(event.getY()));
break;
case MotionEvent.ACTION_MOVE:
verticalView.setCurrPickedCharIndex(verticalView.getPickedCharIndex(event.getY()));
break;
case MotionEvent.ACTION_UP:
verticalView.setCurrPickedCharIndex(-1);
break;
case MotionEvent.ACTION_CANCEL:
verticalView.setCurrPickedCharIndex(-1);
break;
}
return true;
}
});
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: