android中自定义view---实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色
2015-12-18 11:35
901 查看
android自定义view,实现竖直方向的文字功能,文字方向朝上,同时提供接口,判断当前touch的是哪个字符,并改变颜色。
由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如android的自带的TextView强大,只是继承于view,而不是textview。
主要用途:电话本的侧边快速导航等
效果图:(自定义字符串 “#ABCDEFGHIJKLMN),可以实现自定义任意字符串
view的实现:
style文件的定义:(将此代码写入values文件夹下的styles.xml文件中)
布局文件引入此自定义view:
在activity中的使用:
由于时间比较仓促,因此没有对代码进行过多的优化,功能远远不如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; } });
相关文章推荐
- Android studio使用过程中遇到的问题
- Android Call_01_basic
- android usb accessory
- Android Studio 使用 Gradle 打包 Jar
- MAC Android Studio 快捷键
- Android图形图像处理:canvas的save()和restore()函数详解
- 如何删除Android-studio中的整个项目
- 一、初识Android世界
- Android开发-使用自定义View实现loading效果
- 安卓开发学习之018 创建复合控件
- android subclipse subversive
- Android studio中如何使用Ndk(Jni)?
- greenDAO系列2--如何开始
- Android ViewDragHelper完全解析 自定义ViewGroup神器
- android scrollview嵌套listView和gridView的问题。
- Android 5.x Theme 与 ToolBar 实战
- Android 开发笔记——通过 Intent 传递类对象
- Android(Lollipop/5.0) Material Design(二) 入门指南
- vlc-android1.8.0的全部源代码[包括C语言]
- 读博文学Android