2.自定义控件(二)

继承已有View实现自定义View

通过对android原生控件的研究,可以发现android中的控件都是继承view类,如textView、ImageView等,通过重写相关的方法来实现新的效果,通过这个我们得到两点:

我们可以在已有控件的基础上,通过重写相关方法来实现我们的需求。

继承view类或viewgroup类,来创建我们所需要的控件。一般来讲,通过继承已有的控件,来自定义控件要简单一点。

1.开关

这其实是俩张图片

主要步骤:

1、自定义类MyToggleButton继承自View

2、重写onMeasure方法,指定控件大小。

3、重写onDraw方法,绘制控件内容。

4、重写onTouchEvent方法,对touch事件进行解析。

MyToggleButton

自定义属性

  1. <resources
  2. <!-- 声名属性集的名称 -->
  3. <declare-styleable name="MyToggleBtn">
  4. <!-- 声名一个属性 name是my_background 类型为 引用类型 引用资源ID -->
  5. <attr name="my_background" format="reference" />
  6. <!-- 声名一个属性 name是my_slide_btn 类型为 引用类型 引用资源ID -->
  7. <attr name="my_slide_btn" format="reference" />
  8. <!-- 声名一个属性 name是curr_state 类型为 boolean 类型-->
  9. <attr name="curr_state" format="boolean" />
  10. </declare-styleable>
  11. </resources>

布局

  1. <RelativeLayout
  2. xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:heima="http://schemas.android.com/apk/res/com.itheima.togglebtn28"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity" >
  8. <com.itheima.togglebtn28.MyToggleButton
  9. android:id="@+id/my_toggle_btn"
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"
  12. android:layout_centerHorizontal="true"
  13. android:layout_centerVertical="true"
  14. heima:my_background="@drawable/switch_background"
  15. heima:my_slide_btn="@drawable/slide_button"
  16. heima:curr_state="false"
  17. testAttrs="@drawable/ic_launcher"
  18. />
  19. </RelativeLayout>

代码

  1. public class MyToggleButton extends View implements OnClickListener{
  2. /**
  3. * 做为背景的图片
  4. */
  5. private Bitmap backgroundBitmap;
  6. /**
  7. * 可以滑动的图片
  8. */
  9. private Bitmap slideBtn;
  10. private Paint paint;
  11. /**
  12. * 滑动按钮的左边届
  13. */
  14. private float slideBtn_left;
  15. /**
  16. * 背景图的资源ID
  17. */
  18. private int backgroundId;
  19. /**
  20. * 滑动图片的资源ID
  21. */
  22. private int slideBtnId;
  23. /**
  24. * 在代码里面创建对象的时候,使用此构造方法
  25. */
  26. public MyToggleButton(Context context) {
  27. super(context);
  28. // TODO Auto-generated constructor stub
  29. }
  30. /**
  31. * 在布局文件中声名的view,创建时由系统自动调用。
  32. * @param context 上下文对象
  33. * @param attrs 属性集
  34. */
  35. public MyToggleButton(Context context, AttributeSet attrs) {
  36. super(context, attrs);
  37. //无命名空间测试
  38. String testAttrs = attrs.getAttributeValue(null, "testAttrs");
  39. System.out.println("testAttrs===:"+testAttrs);
  40. //获得自定义的属性
  41. TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn);
  42. int N = ta.getIndexCount();
  43. for (int i = 0; i < N; i++) {
  44. /*
  45. * 获得某个属性的ID值
  46. */
  47. int itemId = ta.getIndex(i);
  48. switch (itemId) {
  49. case R.styleable.MyToggleBtn_curr_state:
  50. currState = ta.getBoolean(itemId, false);
  51. break;
  52. case R.styleable.MyToggleBtn_my_background:
  53. backgroundId = ta.getResourceId(itemId, -1);
  54. if(backgroundId == -1){
  55. throw new RuntimeException("请设置背景图片");
  56. }
  57. backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundId);
  58. break;
  59. case R.styleable.MyToggleBtn_my_slide_btn:
  60. slideBtnId = ta.getResourceId(itemId, -1);
  61. slideBtn = BitmapFactory.decodeResource(getResources(), slideBtnId);
  62. break;
  63. default:
  64. break;
  65. }
  66. }
  67. initView();
  68. }
  69. /**
  70. * 初始化
  71. */
  72. private void initView() {
  73. //初始化图片
  74. // backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
  75. // slideBtn = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
  76. //初始化 画笔
  77. paint = new Paint();
  78. paint.setAntiAlias(true); // 打开抗矩齿
  79. //添加onclick事件监听
  80. setOnClickListener(this);
  81. flushState();
  82. }
  83. /*
  84. * view 对象显示的屏幕上,有几个重要步骤:
  85. * 1、构造方法 创建 对象。
  86. * 2、测量view的大小。 onMeasure(int,int);
  87. * 3、确定view的位置 ,view自身有一些建议权,决定权在 父view手中。 onLayout();
  88. * 4、绘制 view 的内容 。 onDraw(Canvas)
  89. */
  90. @Override
  91. /**
  92. * 测量尺寸时的回调方法
  93. */
  94. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  95. // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  96. /**
  97. * 设置当前view的大小
  98. * width :view的宽度
  99. * height :view的高度 (单位:像素)
  100. */
  101. setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
  102. }
  103. //确定位置的时候调用此方法
  104. //自定义view的时候,作用不大
  105. // @Override
  106. // protected void onLayout(boolean changed, int left, int top, int right,
  107. // int bottom) {
  108. // super.onLayout(changed, left, top, right, bottom);
  109. // }
  110. /**
  111. * 当前开关的状态
  112. * true 为开??
  113. */
  114. private boolean currState = false;
  115. @Override
  116. /**
  117. * 绘制当前view的内容
  118. */
  119. protected void onDraw(Canvas canvas) {
  120. // super.onDraw(canvas);
  121. // 绘制 背景
  122. /*
  123. * backgroundBitmap 要绘制的图片
  124. * left 图片的左边届
  125. * top 图片的上边届
  126. * paint 绘制图片要使用的画笔
  127. */
  128. canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
  129. //绘制 可滑动的按钮
  130. canvas.drawBitmap(slideBtn, slideBtn_left, 0, paint);
  131. }
  132. /**
  133. * 判断是否发生拖动,
  134. * 如果拖动了,就不再响应 onclick 事件
  135. *
  136. */
  137. private boolean isDrag = false;
  138. @Override
  139. /**
  140. * onclick 事件在View.onTouchEvent 中被解析。
  141. * 系统对onclick 事件的解析,过于简陋,只要有down 事件 up 事件,系统即认为 发生了click 事件
  142. *
  143. */
  144. public void onClick(View v) {
  145. /*
  146. * 如果没有拖动,才执行改变状态的动作
  147. */
  148. if(!isDrag){
  149. currState = !currState;
  150. flushState();
  151. }
  152. }
  153. /**
  154. * down 事件时的x值
  155. */
  156. private int firstX;
  157. /**
  158. * touch 事件的上一个x值
  159. */
  160. private int lastX;
  161. @Override
  162. public boolean onTouchEvent(MotionEvent event) {
  163. super.onTouchEvent(event);
  164. switch (event.getAction()) {
  165. case MotionEvent.ACTION_DOWN:
  166. firstX = lastX =(int) event.getX();
  167. isDrag = false;
  168. break;
  169. case MotionEvent.ACTION_MOVE:
  170. //判断是否发生拖动
  171. if(Math.abs(event.getX()-firstX)>5){
  172. isDrag = true;
  173. }
  174. //计算 手指在屏幕上移动的距离
  175. int dis = (int) (event.getX() - lastX);
  176. //将本次的位置 设置给lastX
  177. lastX = (int) event.getX();
  178. //根据手指移动的距离,改变slideBtn_left 的值
  179. slideBtn_left = slideBtn_left+dis;
  180. break;
  181. case MotionEvent.ACTION_UP:
  182. //在发生拖动的情况下,根据最后的位置,判断当前开关的状态
  183. if (isDrag) {
  184. int maxLeft = backgroundBitmap.getWidth() - slideBtn.getWidth(); // slideBtn
  185. // 左边届最大值
  186. /*
  187. * 根据 slideBtn_left 判断,当前应是什么状态
  188. */
  189. if (slideBtn_left > maxLeft / 2) { // 此时应为 打开的状态
  190. currState = true;
  191. } else {
  192. currState = false;
  193. }
  194. flushState();
  195. }
  196. break;
  197. }
  198. flushView();
  199. return true; //将事件消费掉
  200. }
  201. /**
  202. * 刷新当前状态
  203. */
  204. private void flushState() {
  205. if(currState){
  206. slideBtn_left = backgroundBitmap.getWidth()-slideBtn.getWidth();
  207. }else{
  208. slideBtn_left = 0;
  209. }
  210. flushView();
  211. }
  212. /**
  213. * 刷新当前视力
  214. */
  215. private void flushView() {
  216. /*
  217. * 对 slideBtn_left 的值进行判断 ,确保其在合理的位置 即 0<=slideBtn_left <= maxLeft
  218. *
  219. */
  220. int maxLeft = backgroundBitmap.getWidth()-slideBtn.getWidth(); // slideBtn 左边届最大值
  221. //确保 slideBtn_left >= 0
  222. slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;
  223. //确保 slideBtn_left <=maxLeft
  224. slideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;
  225. /*
  226. * 刷新当前视图 导致 执行onDraw执行
  227. */
  228. invalidate();
  229. }
  230. }

注意这个方法是系统的invalidate



为新控件添加自定义的属性

一、在attrs.xml文件中声明属性,如:

<declare-styleable name="MyToggleBtn">   // 声名属性集的名称,即这些属性是属于哪个控件的。

<attr name="current_state" format="boolean"/>   // 声名属性 current_state 格式为 boolean 类型

<attr name="slide_button" format="reference"/>   // 声名属性 slide_button 格式为 reference 类型

</declare-styleable>

所有的format类型,详见注1:

二、在布局文件中使用:在使用之前必须声名命名空间,xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn"

说明:xmlns 是XML name space 的缩写;

heima 可为任意写符

http://schemas.android.com/apk/res/  此为android固定格式;

com.itheima.mytogglebtn  此应用的包名,如manifest配置文件中一致。

布局文件:

<com.itheima.mytogglebtn.MyToggleButton

xmlns:heima="http://schemas.android.com/apk/res/com.itheima.mytogglebtn"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

heima:slide_button="@drawable/slide_button" />

三、在代码中对属性进行解析,主要代码:

TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyToggleBtn); // 由attrs 获得 TypeArray

注1:

format 常用类型

reference 引用

color 颜色

boolean 布尔值

dimension 尺寸值

float 浮点值

integer 整型值

string 字符串

enum 布尔值


2.水波纹

模拟水波纹的效果:

1、自定义类继承View

2、重写onTouchEvent方法,down时,获得坐标点,做为圆环圆心。

3、发送handler信息,对数据进行修改,刷新页面。

4、重写onDraw方法,绘制一个圆环。

5、如果可以执行动画,重复上面第3步。

MyRring:只能点一个点开始执行动画,点另一个点上一个动画就停止了,开始这个

  1. public class MyRring extends View{
  2. /**
  3. * 圆环圆心的X坐标
  4. */
  5. private int cx;
  6. /**
  7. * 圆环圆心的Y坐标
  8. */
  9. private int cy;
  10. private Paint paint;
  11. /**
  12. * 圆环的半径
  13. */
  14. private float radius;
  15. /**
  16. * 线条的厚度
  17. */
  18. private float strokeWidth;
  19. public MyRring(Context context, AttributeSet attrs) {
  20. super(context, attrs);
  21. initView();
  22. }
  23. private void initView() {
  24. //初始化paint
  25. paint = new Paint();
  26. paint.setAntiAlias(true); // 抗矩齿
  27. paint.setColor(Color.RED);
  28. paint.setStyle(Style.STROKE); //刻画,画线条
  29. paint.setStrokeWidth(strokeWidth); //设置条线的厚度
  30. paint.setAlpha(255); //设置透明度 ,0--255 0代表完全透明
  31. //
  32. this.radius =0;
  33. strokeWidth = 0;
  34. }
  35. @Override
  36. /**
  37. * 绘制我们的内容
  38. */
  39. protected void onDraw(Canvas canvas) {
  40. super.onDraw(canvas);
  41. /**
  42. * 绘制圆环
  43. */
  44. canvas.drawCircle(cx, cy, radius, paint);
  45. }
  46. @Override
  47. public boolean onTouchEvent(MotionEvent event) {
  48. super.onTouchEvent(event);
  49. switch (event.getAction()) {
  50. case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心
  51. cx = (int) event.getX();
  52. cy = (int) event.getY();
  53. //初始化画笔
  54. initView();
  55. handler.sendEmptyMessage(0);
  56. break;
  57. }
  58. return true;
  59. }
  60. /*
  61. * 刷新状态
  62. */
  63. private void flushState() {
  64. this.radius+=10;
  65. this.strokeWidth = radius/4;
  66. paint.setStrokeWidth(strokeWidth);
  67. int nextAlpha = paint.getAlpha()-20;
  68. if(nextAlpha<=20){
  69. nextAlpha = 0;
  70. }
  71. paint.setAlpha(nextAlpha);
  72. }
  73. private Handler handler = new Handler(){
  74. public void handleMessage(android.os.Message msg) {
  75. flushState();
  76. // 刷新页面 执行onDraw()方法
  77. invalidate();
  78. if(paint.getAlpha() !=0){
  79. handler.sendEmptyMessageDelayed(0, 100);
  80. }
  81. };
  82. };
  83. @Override
  84. /**
  85. * 大小的测量按系统的默认规则
  86. */
  87. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  88. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  89. }
  90. }

MyRing2

  1. public class MyRing extends View{
  2. /**
  3. * 圆心的X坐标
  4. */
  5. private float cx;
  6. /**
  7. * 圆心的Y坐标
  8. */
  9. private float cy;
  10. /**
  11. * 圆环半径
  12. */
  13. private float radius = 0;
  14. /**
  15. * 默认画笔
  16. */
  17. private Paint paint;
  18. protected boolean isRunning = false;
  19. public MyRing(Context context, AttributeSet attrs) {
  20. super(context, attrs);
  21. initView();
  22. }
  23. private void initView() {
  24. radius = 0;
  25. paint = new Paint();
  26. paint.setAntiAlias(true);
  27. paint.setStyle(Style.STROKE);
  28. paint.setStrokeWidth(radius/4);
  29. paint.setColor(Color.GREEN);
  30. paint.setAlpha(255);
  31. }
  32. /**
  33. * 执行动画
  34. */
  35. private void startAnim() {
  36. isRunning = true;
  37. handler.sendEmptyMessageDelayed(0, 50);
  38. }
  39. @Override
  40. protected void onAttachedToWindow() {
  41. super.onAttachedToWindow();
  42. // startAnim() ;
  43. }
  44. @Override
  45. protected void onDetachedFromWindow() {
  46. super.onDetachedFromWindow();
  47. isRunning = false;
  48. }
  49. private Handler handler = new Handler(){
  50. public void handleMessage(android.os.Message msg) {
  51. // 设置透明度
  52. int alpha = paint.getAlpha();
  53. if (alpha == 0) {
  54. isRunning = false;
  55. }
  56. // alpha -= 10;
  57. //
  58. // if (alpha <= 10) {
  59. // alpha = 0;
  60. // }
  61. alpha = Math.max(0, alpha-10);
  62. paint.setAlpha(alpha);
  63. Log.i("leo", "" + alpha);
  64. // 设置半径
  65. radius += 5;
  66. paint.setStrokeWidth(radius / 3);
  67. invalidate();
  68. if (isRunning) {
  69. handler.sendEmptyMessageDelayed(0, 50);
  70. }
  71. };
  72. };
  73. @Override
  74. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  75. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  76. // setMeasuredDimension(200, 200);
  77. }
  78. @Override
  79. protected void onLayout(boolean changed, int left, int top, int right,
  80. int bottom) {
  81. if(changed){
  82. cx = getWidth()/2;
  83. cy = getHeight()/2;
  84. }
  85. }
  86. @Override
  87. protected void onDraw(Canvas canvas) {
  88. canvas.drawCircle(cx, cy, radius, paint);
  89. }
  90. @Override
  91. public boolean onTouchEvent(MotionEvent event) {
  92. super.onTouchEvent(event);
  93. if(event.getAction() == MotionEvent.ACTION_DOWN){
  94. cx = event.getX();
  95. cy = event.getY();
  96. initView();
  97. startAnim();
  98. }
  99. return true;
  100. }
  101. }

MyRingSimple:可以点俩个点

  1. public class MyRingSimple extends View{
  2. /**
  3. * 圆心的X坐标
  4. */
  5. private float cx;
  6. /**
  7. * 圆心的Y坐标
  8. */
  9. private float cy;
  10. /**
  11. * 圆环半径
  12. */
  13. private float radius = 0;
  14. /**
  15. * 默认画笔
  16. */
  17. private Paint paint;
  18. protected boolean isRunning = false;
  19. private Paint lPaint;
  20. public MyRingSimple(Context context, AttributeSet attrs) {
  21. super(context, attrs);
  22. initView();
  23. }
  24. private void initView() {
  25. radius = 50;
  26. paint = new Paint();
  27. paint.setAntiAlias(true);
  28. paint.setStyle(Style.STROKE);
  29. paint.setStrokeWidth(radius/4);
  30. paint.setColor(Color.GREEN);
  31. paint.setAlpha(255);
  32. lPaint = new Paint();
  33. lPaint.setAntiAlias(true);
  34. lPaint.setStyle(Style.STROKE);
  35. lPaint.setColor(Color.GREEN);
  36. }
  37. @Override
  38. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  39. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  40. setMeasuredDimension(200, 200);
  41. }
  42. @Override
  43. protected void onLayout(boolean changed, int left, int top, int right,
  44. int bottom) {
  45. if(changed){
  46. cx = getWidth()/2;
  47. cy = getHeight()/2;
  48. }
  49. }
  50. @Override
  51. protected void onDraw(Canvas canvas) {
  52. for (int i = 10; i < getWidth(); i=i+20) {
  53. canvas.drawLine(0, i, getWidth(), i, lPaint);
  54. canvas.drawLine(i, 0, i,getHeight(), lPaint);
  55. }
  56. paint.setColor(Color.GREEN);
  57. canvas.translate(-20, -20);
  58. canvas.drawCircle(cx, cy, radius, paint);
  59. }
  60. }

MyRingWave:完整,可以触摸

  1. /**
  2. * 水波纹效果
  3. * @author leo
  4. *
  5. */
  6. public class MyRingWave extends View{
  7. /**
  8. * 二个相临波浪中心点的最小距离
  9. */
  10. private static final int DIS_SOLP = 13;
  11. protected boolean isRunning = false;
  12. private ArrayList<Wave> wList;
  13. public MyRingWave(Context context, AttributeSet attrs) {
  14. super(context, attrs);
  15. wList = new ArrayList<MyRingWave.Wave>();
  16. }
  17. private Handler handler = new Handler(){
  18. public void handleMessage(android.os.Message msg) {
  19. //刷新数据
  20. flushData();
  21. //刷新页面
  22. invalidate();
  23. //循环动画
  24. if (isRunning) {
  25. handler.sendEmptyMessageDelayed(0, 50);
  26. }
  27. };
  28. };
  29. @Override
  30. protected void onDraw(Canvas canvas) {
  31. for (int i = 0; i < wList.size(); i++) {
  32. Wave wave = wList.get(i);
  33. canvas.drawCircle(wave.cx, wave.cy, wave.r, wave.p);
  34. }
  35. }
  36. @Override
  37. public boolean onTouchEvent(MotionEvent event) {
  38. super.onTouchEvent(event);
  39. switch (event.getAction()) {
  40. case MotionEvent.ACTION_DOWN:
  41. case MotionEvent.ACTION_MOVE:
  42. int x = (int) event.getX();
  43. int y = (int) event.getY();
  44. addPoint(x,y);
  45. break;
  46. default:
  47. break;
  48. }
  49. return true;
  50. }
  51. /**
  52. * 添加新的波浪中心点
  53. * @param x
  54. * @param y
  55. */
  56. private void addPoint(int x, int y) {
  57. if(wList.size() == 0){
  58. addPoint2List(x,y);
  59. /*
  60. * 第一次启动动画
  61. */
  62. isRunning = true;
  63. handler.sendEmptyMessage(0);
  64. }else{
  65. Wave w = wList.get(wList.size()-1);
  66. if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){
  67. addPoint2List(x,y);
  68. }
  69. };
  70. }
  71. /**
  72. * 添加新的波浪
  73. * @param x
  74. * @param y
  75. */
  76. private void addPoint2List(int x, int y) {
  77. Wave w = new Wave();
  78. w.cx = x;
  79. w.cy=y;
  80. Paint pa=new Paint();
  81. pa.setColor(colors[(int)(Math.random()*4)]);
  82. pa.setAntiAlias(true);
  83. pa.setStyle(Style.STROKE);
  84. w.p = pa;
  85. wList.add(w);
  86. }
  87. private int [] colors = new int[]{Color.BLUE,Color.RED,Color.YELLOW,Color.GREEN};
  88. /**
  89. * 刷新数据
  90. */
  91. private void flushData() {
  92. for (int i = 0; i < wList.size(); i++) {
  93. Wave w = wList.get(i);
  94. //如果透明度为 0 从集合中删除
  95. int alpha = w.p.getAlpha();
  96. if(alpha == 0){
  97. wList.remove(i); //删除i 以后,i的值应该再减1 否则会漏掉一个对象,不过,在此处影响不大,效果上看不出来。
  98. continue;
  99. }
  100. alpha-=5;
  101. if(alpha<5){
  102. alpha =0;
  103. }
  104. //降低透明度
  105. w.p.setAlpha(alpha);
  106. //扩大半径
  107. w.r = w.r+3;
  108. //设置半径厚度
  109. w.p.setStrokeWidth(w.r/3);
  110. }
  111. /*
  112. * 如果集合被清空,就停止刷新动画
  113. */
  114. if(wList.size() == 0){
  115. isRunning = false;
  116. }
  117. }
  118. /**
  119. * 定义一个波浪
  120. * @author leo
  121. */
  122. private class Wave {
  123. //圆心
  124. int cx;
  125. int cy;
  126. //画笔
  127. Paint p;
  128. //半径
  129. int r;
  130. }
  131. }

来自为知笔记(Wiz)

附件列表

时间: 2024-10-09 00:26:06

2.自定义控件(二)的相关文章

android 自定义控件二之仿QQ长按删除

自定义Dialog 1.先上个效果图: 虽然效果丑了点,但主要学习修改已有的控件,例如修改Dialog控件 2.一些基本的只是进行了解 Dialog: theme是Dialog的样式,常用样式为: <style name="MyDialogStyle" parent="@android:Theme.Dialog"> <item name="android:windowFrame">@null</item> &l

android自定义控件(二) 入门,继承View

转载请注明地址:http://blog.csdn.net/ethan_xue/article/details/7313788 ps: 可根据apidemo里LableView,list4,list6学习 文档在dev guide/Framework Topics/User Interface/Building Custom Components 自定义控件的步骤: 1 View的工作原理  2 编写View类  3 为View类增加属性  4 绘制屏幕  5 响应用户消息  6 自定义回调函数

android 自定义控件 (二) 初步认识

最近一直在忙项目,也在不断的面试,每次问道这个自定义控件,好多人云里雾绕的,今天就这个机会,简单做个完全自定义控件的入门吧.上一篇讲了继承已有控件的过程,发现我们只是简答的在封装的布局里操作,并没有重写onDraw,onMeasure,onLayout这些方法.其实继承控件这种形式基本能满足我们大部分的功能,但对于现有控件无法满足的怎么办,那就让我们重写上述三个方法,自己写特定需求的控件.完全自定义控件一般有两种,一种继承View,一种继承Viewgroup.根据view树结构,我们知道View

玩转android自定义控件二——自定义索引栏listview

带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样: 今天,我们就从零到一实现这个具有索引栏的listview. 怎么实现这个控件了,我们应当梳理出一个思路. ①首先应当将字母的索引栏继承与一个控件,通过ondraw方法将字母画出来. ②然后我们应该监听这个字母控件的ontouch事件,来判断用户到底是按了那个字母. ③就是实现这个索引栏与listview的联动,就是将listview滑动到按下字母的位置. 大体流程图如下: 有了前面铺垫,我们引出

老猪带你玩转android自定义控件二——自定义索引栏listview

带索引栏的listview,在android开发非常普遍,方便用户进行字母索引,就像微信通讯录这样: 今天,我们就从零到一实现这个具有索引栏的listview. 怎么实现这个控件了,我们应当梳理出一个思路. ①首先应当将字母的索引栏继承与一个控件,通过ondraw方法将字母画出来. ②然后我们应该监听这个字母控件的ontouch事件,来判断用户到底是按了那个字母. ③就是实现这个索引栏与listview的联动,就是将listview滑动到按下字母的位置. 大体流程图如下: 有了前面铺垫,我们引出

【开源】EnterpriseFrameWork框架系列文章索引

一.EnterpriseFrameWork框架总体介绍 二.利用EnterpriseFrameWork快速开发Web系统(B/S) 三.利用EnterpriseFrameWork快速开发Winform系统(C/S) 四.利用EnterpriseFrameWork快速开发基于WCF为中间件的三层结构系统 五.利用EnterpriseFrameWork快速开发基于WebServices的接口 六.EnterpriseFrameWork框架基础功能之权限管理 七.EnterpriseFrameWork

Python爬取CSDN博客文章

之前解析出问题,刚刚看到,这次仔细审查了 0 url :http://blog.csdn.net/youyou1543724847/article/details/52818339Redis一点基础的东西目录 1.基础底层数据结构 2.windows下环境搭建 3.java里连接redis数据库 4.关于认证 5.redis高级功能总结1.基础底层数据结构1.1.简单动态字符串SDS定义: ...47分钟前1 url :http://blog.csdn.net/youyou1543724847/

二十五、【开源】EFW框架Winform前端开发之强大的自定义控件库

回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan.baidu.com/s/1o6MAKCa       前言:相比以前现在做Net系统Winform版开发有几款不错的控件,如DotNetBar.DevExpress,EFW框架也不能落后加入了DotNetBar控件,有时间也想把DevExpress控件也整合进来,这样让大家又多一个选择:DotNetBar中

Android 自定义控件开发入门(二)

上一次我们讲了一堆实现自定义控件的理论基础,列举了View类一些可以重写的方法,我们对这些方法的重写是我们继承View类来派生自定义控件的关键 我通过一个最简单的例子给大家展示了这一个过程,无论是多么复杂的自定义控件,思路总是这样子的,但是因为我们仅仅重写了onDraw方法使得大家觉得怪怪的,作为一个控件,我们居然还要为了他的实现为其增加麻烦的监听,这就不能叫做控件了. 下面再给大家介绍一个经常重写的方法法:publicboolean onTouchEvent (MotionEvent even