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

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

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

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

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

view的实现:

  1 import cn.carbs.verticalstraighttextview.R;
  2 import android.content.Context;
  3 import android.content.res.TypedArray;
  4 import android.graphics.Canvas;
  5 import android.graphics.Paint.Align;
  6 import android.graphics.Rect;
  7 import android.text.TextPaint;
  8 import android.util.AttributeSet;
  9 import android.util.Log;
 10 import android.util.TypedValue;
 11 import android.view.View;
 12 /**
 13  * 参考资料:
 14  *        http://chris.banes.me/2014/03/27/measuring -text/
 15  *        http://blog.163.com/gobby_1110/blog/static/2928171520136304172378/
 16  * @author Rick.Wang
 17  *
 18  */
 19 public class VerticalStraightTextView extends View {
 20
 21      private final static int DEFAULT_TEXT_SIZE = 15;
 22     private final static int DEFAULT_TEXT_COLOR = 0xFF000000;
 23     private final static int DEFAULT_TEXT_COLOR_PICKED = 0xFF990000;
 24     private final static int DEFAULT_CHAR_SPACE = 0;
 25
 26     private TextPaint mTextPaint;
 27     private TextPaint mTextPaintPicked;
 28     private String mText = "";
 29
 30     private int mTextLength = 0;
 31     private int mCharGap = 0;
 32     private int mCharWidth = 0;
 33     private int mCharHeight = 0;
 34
 35     float[] coordinates = null ;
 36
 37     public float[] getCoordinates(){
 38      return coordinates;
 39     }
 40
 41     public VerticalStraightTextView(Context context) {
 42         super(context);
 43         init();
 44     }
 45
 46     public VerticalStraightTextView(Context context, AttributeSet attrs) {
 47         super(context, attrs);
 48         init();
 49
 50         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.verticalstraighttextview );
 51
 52         int n = a.getIndexCount();
 53         for (int i = 0; i < n; i++) {
 54             int attr = a.getIndex(i);
 55             switch (attr) {
 56             case R.styleable.verticalstraighttextview_text :
 57                mText = a.getString(attr);
 58                if(mText == null){
 59                     mText = "";
 60                     break;
 61               }
 62                mTextLength = mText .length();
 63                 break;
 64             case R.styleable.verticalstraighttextview_textSize :
 65                int textSize = a.getDimensionPixelOffset(R.styleable.verticalstraighttextview_textSize , DEFAULT_TEXT_SIZE);
 66                 if (textSize > 0) {
 67                     mTextPaint.setTextSize(textSize);
 68                     mTextPaintPicked.setTextSize(textSize);
 69                 }
 70                break;
 71
 72             case R.styleable.verticalstraighttextview_charGap :
 73                mCharGap = a.getDimensionPixelSize(R.styleable.verticalstraighttextview_charGap , (int) TypedValue.applyDimension(
 74                         TypedValue. COMPLEX_UNIT_PX, DEFAULT_CHAR_SPACE, getResources().getDisplayMetrics()));
 75                 break;
 76             case R.styleable.verticalstraighttextview_textColor :
 77                  mTextPaint .setColor(a.getColor(R.styleable.verticalstraighttextview_textColor, DEFAULT_TEXT_COLOR));
 78                 break;
 79             case R.styleable.verticalstraighttextview_textColorPicked :
 80                  mTextPaintPicked .setColor(a.getColor(R.styleable.verticalstraighttextview_textColorPicked, DEFAULT_TEXT_COLOR_PICKED ));
 81                 break;
 82             }
 83         }
 84         a.recycle();
 85
 86         requestLayout();
 87         invalidate();
 88     }
 89
 90     private final void init() {
 91         mTextPaint = new TextPaint();
 92         mTextPaint.setAntiAlias(true);
 93         mTextPaint.setTextSize(DEFAULT_TEXT_SIZE);
 94         mTextPaint.setTextAlign(Align.CENTER);
 95         mTextPaintPicked = new TextPaint(mTextPaint);
 96         mTextPaint.setColor(DEFAULT_TEXT_COLOR);
 97         mTextPaintPicked.setColor(DEFAULT_TEXT_COLOR_PICKED);
 98     }
 99
100     public void setText(String text) {
101      if(text == null){
102           text = "";
103      }
104      if(!mText.equals(text)){
105            mText = text;
106            mTextLength = text.length();
107           requestLayout();
108           invalidate();
109      }
110     }
111
112     public void setTextSize(int size) {
113      if(mTextPaint.getTextSize() != size){
114            mTextPaint.setTextSize(size);
115            mTextPaintPicked.setTextSize(size);
116             requestLayout();
117             invalidate();
118      }
119     }
120
121     public void setTextColor(int color) {
122      if(color != mTextPaint.getColor()){
123            mTextPaint.setColor(color);
124           invalidate();
125      }
126     }
127
128     public void setTextColorPicked(int color) {
129      if(color != mTextPaintPicked.getColor()){
130            mTextPaintPicked.setColor(color);
131           invalidate();
132      }
133     }
134
135     public int getCharHeight(){
136      return mCharGap + mCharHeight;
137     }
138
139     @Override
140     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
141      Log.d("1218" , "onMeasure" );
142      //获取字体宽度
143      float maxCharWidth = 0f;
144      for(int i = 0; i < mTextLength; i++){
145            maxCharWidth = Math.max(mTextPaint.measureText( mText.substring(i, i+1)), maxCharWidth);
146      }
147      mCharWidth = ( int)Math.ceil(maxCharWidth);
148
149      //获取字体高度
150      Rect textBounds = new Rect();
151      mTextPaint.getTextBounds( mText, 0, mTextLength, textBounds);
152      mCharHeight = textBounds.height();
153
154      setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
155     }
156
157     private int measureWidth(int measureSpec) {
158         int result = 0;
159         int specMode = MeasureSpec.getMode(measureSpec);
160         int specSize = MeasureSpec.getSize(measureSpec);
161
162         if (specMode == MeasureSpec.EXACTLY) {
163             result = specSize;
164         } else {
165           result = this.getPaddingLeft() + this.getPaddingRight() + mCharWidth ;
166             if (specMode == MeasureSpec.AT_MOST) {
167                 result = Math. min(result, specSize);
168             }
169         }
170         return result;
171     }
172
173     private int measureHeight(int measureSpec) {
174         int result = 0;
175         int specMode = MeasureSpec.getMode(measureSpec);
176         int specSize = MeasureSpec.getSize(measureSpec);
177
178         if (specMode == MeasureSpec.EXACTLY) {
179             result = specSize;
180         } else {
181           result = getPaddingTop() + getPaddingBottom();
182            if(mTextLength > 0){
183               result += mTextLength * (mCharGap + mCharHeight) - mCharGap ;
184           }
185             if (specMode == MeasureSpec.AT_MOST) {
186                 result = Math. min(result, specSize);
187             }
188         }
189         return result;
190     }
191
192     int pickedCharIndex = -1;
193
194     @Override
195     protected void onDraw(Canvas canvas) {
196         super.onDraw(canvas);
197         Log. d("1218", "onDraw");
198         if(mTextLength == 0){
199            return;
200         }
201
202         int height = getMeasuredHeight();
203         int measuredWidth = getMeasuredWidth();
204
205         int paddingTop = getPaddingTop();
206         int paddingBottom = getPaddingBottom();
207         int paddingLeft = getPaddingLeft();
208         int paddingRight = getPaddingRight();
209
210         //默认居中
211         int x = paddingLeft + (measuredWidth - paddingLeft - paddingRight)/2;
212         int y = 0;
213
214         int cellHeight = (height - paddingTop - paddingBottom)/ mTextLength ;
215         //TODO 可能会有bug
216         if(coordinates == null || coordinates. length != mTextLength){
217            coordinates = new float[mTextLength + 1];
218         }
219         coordinates[0] = 0;
220         for(int i = 0; i < mTextLength; i++){
221           y = paddingTop + i * cellHeight + cellHeight/2;
222            coordinates[i + 1] = y + cellHeight/2;
223            if(pickedCharIndex != i){
224               canvas.drawText( mText, i, i + 1, x, y, mTextPaint);
225           } else{
226               canvas.drawText( mText, i, i + 1, x, y, mTextPaintPicked);
227           }
228         }
229         coordinates[mTextLength ] = height;
230     }
231
232     //y is the coordinate-Y
233     //this function can return the "touched char"
234     public int getPickedCharIndex(float[] coordinates, float y){
235      int start = 0;
236      int end = coordinates. length - 1;
237      while (start != end - 1) {
238             int middle = (start + end) / 2;
239             if (y < coordinates[middle]) {
240                 end = middle;
241             } else if (y > coordinates[middle]) {
242                 start = middle;
243             }
244         }
245      return start;
246     }
247
248     public int getPickedCharIndex(float y){
249      int start = 0;
250      int end = coordinates.length - 1;
251      while (start != end - 1) {
252             int middle = (start + end) / 2;
253             if (y < coordinates [middle]) {
254                 end = middle;
255             } else if (y > coordinates[middle]) {
256                 start = middle;
257             }
258         }
259      return start;
260     }
261
262     public void setPickedCharIndex(int index){
263      if(pickedCharIndex != index){
264            pickedCharIndex = index;
265           invalidate();
266      }
267     }
268 }

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

1 <declare-styleable name="verticalstraighttextview">
2         <attr name= "text" format ="string" />
3         <attr name= "textColor" format ="reference|color" />
4         <attr name= "textColorPicked" format="reference|color" />
5         <attr name= "textSize" format="reference|dimension" />
6         <attr name= "charGap" format ="reference|dimension" />
7     </declare-styleable >

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

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

在activity中的使用:

 1 verticalView = (VerticalStraightTextView)this.findViewById(R.id.kk);
 2
 3         verticalView.setOnClickListener(new View.OnClickListener() {
 4             @Override
 5             public void onClick(View v) {
 6                 Toast.makeText(getApplicationContext(), "onclick", Toast.LENGTH_SHORT).show();
 7             }
 8         });
 9
10         verticalView.setOnTouchListener(new View.OnTouchListener() {
11
12             @Override
13             public boolean onTouch(View view, MotionEvent event) {
14                 switch(event.getAction()){
15                 case MotionEvent.ACTION_DOWN:
16                     verticalView.setPickedCharIndex(verticalView.getPickedCharIndex(event.getY()));
17                     break;
18                 case MotionEvent.ACTION_MOVE:
19                     verticalView.setPickedCharIndex(verticalView.getPickedCharIndex(event.getY()));
20                     break;
21                 case MotionEvent.ACTION_UP:
22                     verticalView.setPickedCharIndex(-1);
23                     break;
24                 case MotionEvent.ACTION_CANCEL:
25                     verticalView.setPickedCharIndex(-1);
26                     break;
27                 }
28                 return true;
29             }
30         });
时间: 2024-10-05 06:00:00

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

android中自定义view涉及到的绘制知识

android中自定义view的过程中,需要了解的绘制知识. 1.画笔paint: 画笔设置: <span style="font-size:14px;"> paint.setAntiAlias(true);//抗锯齿功能 paint.setColor(Color.RED); //设置画笔颜色 paint.setStyle(Style.FILL);//设置填充样式 paint.setStrokeWidth(30);//设置画笔宽度 paint.setShadowLayer(

Android中自定义View的MeasureSpec使用

有时,Android系统控件无法满足我们的需求,因此有必要自定义View.具体方法参见官方开发文档:http://developer.android.com/guide/topics/ui/custom-components.html 一般来说,自定义控件都会去重写View的onMeasure方法,因为该方法指定该控件在屏幕上的大小. protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec) onMeasure传

Android高手进阶教程(三)之----Android 中自定义View的应用.

大家好我们今天的教程是在Android 教程中自定义View 的学习,对于初学着来说,他们习惯了Android 传统的页面布局方式,如下代码: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertic

Android 自定义View实现竖直跑马灯效果

首先给出效果图 中间的色块是因为视频转成GIF造成的失真,自动忽略哈. 大家知道,横向的跑马灯android自带的TextView就可以实现,详情请百度[Android跑马灯效果].但是竖直的跑马灯效果原生Android是不支持的.网上也有很多网友实现了自定义的效果,但是我一贯是不喜欢看别人的代码,所以这篇博客的思路完全是我自己的想法哈. 首先,我们需要给自定义的控件梳理一下格局,如下图所示: 1.首先我们将控件分为三个区块,上面绿色部分为消失不可见的块,中间黑色部分为可见区域,下面红色部分为欲

Android 中自定义View的初步总结

概述 在开发过程中,经常会遇到系统中提供的控件无法满足产品的设计需求,这时可能就需要考虑使用自定义的View来实现产品的设计细节了.对于自定义View,可以分为两种,一种是自定义控件(继承View),另一种是自定义布局容器(继承ViewGroup),下面就针对自定义控件View的应用进行简单的总结. 自定义View 自定义View时,我们大部分只需要重写两个方法onMeasure(),onDraw().onMeasure()负责对当前View尺寸进行测量,onDraw()负责把当前这个View绘

Android中自定义View、ViewGroup理论基础详解

Android自身提供了许多widgets,但是有时候这些widgets并不能满足我们的需求,这时我们就需要自定义View,本文会详细说明自定义View的各种理论基础,只有理解了这些知识,我们才能更好地实现各种功能的控件. 我觉得自定义View中最重要的部分就是绘图和交互,自定义的绘图使得你的View与众不同,交互使用户可以与你的View进行交互,而绘图的前提是View的量算与布局,交互的基础是触摸事件,所以量算.布局.绘图.触摸事件这些是自定义View的核心. 除此之外,一个设计友好的自定义V

Android中自定义视图View之---前奏篇

前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧.关于这篇blog,网上已经有很多案例了,其实没什么难度的.但是我们在开发的过程中有时候会用到一些自定义的View以达到我们所需要的效果.其实网上的很多案例我们看完之后,发现这部分没什么难度的,我总结了两点: 1.准备纸和笔,计算坐标 2.在onDraw方法中开始画图,invalidate方法刷新,onTouchEvent方法监听触摸事件 对于绘图相关的知识,之前在弄JavaSE相关的知识的时候,

[转]Android中自定义样式与View的构造函数中的第三个参数defStyle的意义

转自:http://www.cnblogs.com/angeldevil/p/3479431.html Android中自定义样式与View的构造函数中的第三个参数defStyle的意义 零.序 一.自定义Style 二.在XML中为属性声明属性值 1. 在layout中定义属性 2. 设置Style 3. 通过Theme指定 三.在运行时获取属性值 1. View的第三个构造函数的第三个参数defStyle 2. obtailStyledAttributes 3. Example 四.结论与代

Android中自定义视图View之---开发案例

自定义视图View的案例 下面我们就是开始正式的进入自定义视图View了 在讲解正式内容之前,我们先来看一下基本知识 1.我们在自定义视图View的时候正确的步骤和方法 1).必须定义有Context/Attrbuite参数的构造方法,并且调用父类的方法 public LabelView(Context context, AttributeSet attrs) 不然会报错: 2).重写onMeasure方法 @Override protected void onMeasure(int width