首先看效果图,

看下这两个界面,第一个中用到了一个自定义的FlowRadioGroup,支持复合子控件,自定义布局;

第二个界面中看到了输入的数字 自动4位分割了吧;也用到了自定义的DivisionEditText控件。

下面直接看源码FlowRadioGroup了;

  1 /*
  2  * Copyright (C) 2006 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16
 17 package com.newgame.sdk.view;
 18
 19 import java.util.ArrayList;
 20
 21 import android.content.Context;
 22 import android.content.res.TypedArray;
 23 import android.util.AttributeSet;
 24 import android.view.View;
 25 import android.view.ViewGroup;
 26 import android.widget.CompoundButton;
 27 import android.widget.LinearLayout;
 28 import android.widget.RadioButton;
 29
 30 /** 可以放多种布局控件,能找到radiobutton */
 31 public class FlowRadioGroup extends LinearLayout {
 32     // holds the checked id; the selection is empty by default
 33     private int mCheckedId = -1;
 34     // tracks children radio buttons checked state
 35     private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;
 36     // when true, mOnCheckedChangeListener discards events
 37     private boolean mProtectFromCheckedChange = false;
 38     private OnCheckedChangeListener mOnCheckedChangeListener;
 39     private PassThroughHierarchyChangeListener mPassThroughListener;
 40
 41     // 存放当前的radioButton
 42     private ArrayList<RadioButton> radioButtons;
 43
 44     public FlowRadioGroup(Context context) {
 45         super(context);
 46         setOrientation(VERTICAL);
 47         init();
 48     }
 49
 50     public FlowRadioGroup(Context context, AttributeSet attrs) {
 51         super(context, attrs);
 52         init();
 53     }
 54
 55     private void init() {
 56         mChildOnCheckedChangeListener = new CheckedStateTracker();
 57         mPassThroughListener = new PassThroughHierarchyChangeListener();
 58         super.setOnHierarchyChangeListener(mPassThroughListener);
 59         radioButtons = new ArrayList<RadioButton>();
 60     }
 61
 62     @Override
 63     public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
 64         // the user listener is delegated to our pass-through listener
 65         mPassThroughListener.mOnHierarchyChangeListener = listener;
 66     }
 67
 68     @Override
 69     protected void onFinishInflate() {
 70         super.onFinishInflate();
 71
 72         // checks the appropriate radio button as requested in the XML file
 73         if (mCheckedId != -1) {
 74             mProtectFromCheckedChange = true;
 75             setCheckedStateForView(mCheckedId, true);
 76             mProtectFromCheckedChange = false;
 77             setCheckedId(mCheckedId);
 78         }
 79     }
 80
 81     @Override
 82     public void addView(View child, int index, ViewGroup.LayoutParams params) {
 83         if (child instanceof RadioButton) {
 84             final RadioButton button = (RadioButton) child;
 85             radioButtons.add(button);
 86
 87             if (button.isChecked()) {
 88                 mProtectFromCheckedChange = true;
 89                 if (mCheckedId != -1) {
 90                     setCheckedStateForView(mCheckedId, false);
 91                 }
 92                 mProtectFromCheckedChange = false;
 93                 setCheckedId(button.getId());
 94             }
 95         } else if (child instanceof ViewGroup) {// 如果是复合控件
 96             // 遍历复合控件
 97             ViewGroup vg = ((ViewGroup) child);
 98             setCheckedView(vg);
 99         }
100
101         super.addView(child, index, params);
102     }
103
104     /** 查找复合控件并设置radiobutton */
105     private void setCheckedView(ViewGroup vg) {
106         int len = vg.getChildCount();
107         for (int i = 0; i < len; i++) {
108             if (vg.getChildAt(i) instanceof RadioButton) {// 如果找到了,就设置check状态
109                 final RadioButton button = (RadioButton) vg.getChildAt(i);
110                 // 添加到容器
111                 radioButtons.add(button);
112                 if (button.isChecked()) {
113                     mProtectFromCheckedChange = true;
114                     if (mCheckedId != -1) {
115                         setCheckedStateForView(mCheckedId, false);
116                     }
117                     mProtectFromCheckedChange = false;
118                     setCheckedId(button.getId());
119                 }
120             } else if (vg.getChildAt(i) instanceof ViewGroup) {// 迭代查找并设置
121                 ViewGroup childVg = (ViewGroup) vg.getChildAt(i);
122                 setCheckedView(childVg);
123             }
124         }
125     }
126
127     /** 查找复合控件并设置id */
128     private void setCheckedId(ViewGroup vg) {
129         int len = vg.getChildCount();
130         for (int i = 0; i < len; i++) {
131             if (vg.getChildAt(i) instanceof RadioButton) {// 如果找到了,就设置check状态
132                 final RadioButton button = (RadioButton) vg.getChildAt(i);
133                 int id = button.getId();
134                 // generates an id if it's missing
135                 if (id == View.NO_ID) {
136                     id = button.hashCode();
137                     button.setId(id);
138                 }
139                 button.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
140             } else if (vg.getChildAt(i) instanceof ViewGroup) {// 迭代查找并设置
141                 ViewGroup childVg = (ViewGroup) vg.getChildAt(i);
142                 setCheckedId(childVg);
143             }
144         }
145     }
146
147     /** 查找radioButton控件 */
148     public RadioButton findRadioButton(ViewGroup group) {
149         RadioButton resBtn = null;
150         int len = group.getChildCount();
151         for (int i = 0; i < len; i++) {
152             if (group.getChildAt(i) instanceof RadioButton) {
153                 resBtn = (RadioButton) group.getChildAt(i);
154             } else if (group.getChildAt(i) instanceof ViewGroup) {
155                 resBtn = findRadioButton((ViewGroup) group.getChildAt(i));
156                 findRadioButton((ViewGroup) group.getChildAt(i));
157                 break;
158             }
159         }
160         return resBtn;
161     }
162
163     /** 返回当前radiobutton控件的count */
164     public int getRadioButtonCount() {
165         return radioButtons.size();
166     }
167
168     /** 返回当前index的radio */
169     public RadioButton getRadioButton(int index) {
170         return radioButtons.get(index);
171     }
172
173     /**
174      * <p>
175      * Sets the selection to the radio button whose identifier is passed in
176      * parameter. Using -1 as the selection identifier clears the selection;
177      * such an operation is equivalent to invoking {@link #clearCheck()}.
178      * </p>
179      *
180      * @param id
181      *            the unique id of the radio button to select in this group
182      *
183      * @see #getCheckedRadioButtonId()
184      * @see #clearCheck()
185      */
186     public void check(int id) {
187         // don't even bother
188         if (id != -1 && (id == mCheckedId)) {
189             return;
190         }
191
192         if (mCheckedId != -1) {
193             setCheckedStateForView(mCheckedId, false);
194         }
195
196         if (id != -1) {
197             setCheckedStateForView(id, true);
198         }
199
200         setCheckedId(id);
201     }
202
203     private void setCheckedId(int id) {
204         mCheckedId = id;
205         if (mOnCheckedChangeListener != null) {
206             mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
207         }
208     }
209
210     private void setCheckedStateForView(int viewId, boolean checked) {
211         View checkedView = findViewById(viewId);
212         if (checkedView != null && checkedView instanceof RadioButton) {
213             ((RadioButton) checkedView).setChecked(checked);
214         }
215     }
216
217     /**
218      * <p>
219      * Returns the identifier of the selected radio button in this group. Upon
220      * empty selection, the returned value is -1.
221      * </p>
222      *
223      * @return the unique id of the selected radio button in this group
224      *
225      * @see #check(int)
226      * @see #clearCheck()
227      */
228     public int getCheckedRadioButtonId() {
229         return mCheckedId;
230     }
231
232     /**
233      * <p>
234      * Clears the selection. When the selection is cleared, no radio button in
235      * this group is selected and {@link #getCheckedRadioButtonId()} returns
236      * null.
237      * </p>
238      *
239      * @see #check(int)
240      * @see #getCheckedRadioButtonId()
241      */
242     public void clearCheck() {
243         check(-1);
244     }
245
246     /**
247      * <p>
248      * Register a callback to be invoked when the checked radio button changes
249      * in this group.
250      * </p>
251      *
252      * @param listener
253      *            the callback to call on checked state change
254      */
255     public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
256         mOnCheckedChangeListener = listener;
257     }
258
259     /**
260      * {@inheritDoc}
261      */
262     @Override
263     public LayoutParams generateLayoutParams(AttributeSet attrs) {
264         return new FlowRadioGroup.LayoutParams(getContext(), attrs);
265     }
266
267     /**
268      * {@inheritDoc}
269      */
270     @Override
271     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
272         return p instanceof FlowRadioGroup.LayoutParams;
273     }
274
275     @Override
276     protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
277         return new LayoutParams(LayoutParams.WRAP_CONTENT,
278                 LayoutParams.WRAP_CONTENT);
279     }
280
281     /**
282      * <p>
283      * This set of layout parameters defaults the width and the height of the
284      * children to {@link #WRAP_CONTENT} when they are not specified in the XML
285      * file. Otherwise, this class ussed the value read from the XML file.
286      * </p>
287      *
288      * <p>
289      * See {@link android.R.styleable#LinearLayout_Layout LinearLayout
290      * Attributes} for a list of all child view attributes that this class
291      * supports.
292      * </p>
293      *
294      */
295     public static class LayoutParams extends LinearLayout.LayoutParams {
296         /**
297          * {@inheritDoc}
298          */
299         public LayoutParams(Context c, AttributeSet attrs) {
300             super(c, attrs);
301         }
302
303         /**
304          * {@inheritDoc}
305          */
306         public LayoutParams(int w, int h) {
307             super(w, h);
308         }
309
310         /**
311          * {@inheritDoc}
312          */
313         public LayoutParams(int w, int h, float initWeight) {
314             super(w, h, initWeight);
315         }
316
317         /**
318          * {@inheritDoc}
319          */
320         public LayoutParams(ViewGroup.LayoutParams p) {
321             super(p);
322         }
323
324         /**
325          * {@inheritDoc}
326          */
327         public LayoutParams(MarginLayoutParams source) {
328             super(source);
329         }
330
331         /**
332          * <p>
333          * Fixes the child's width to
334          * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the
335          * child's height to
336          * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} when not
337          * specified in the XML file.
338          * </p>
339          *
340          * @param a
341          *            the styled attributes set
342          * @param widthAttr
343          *            the width attribute to fetch
344          * @param heightAttr
345          *            the height attribute to fetch
346          */
347         @Override
348         protected void setBaseAttributes(TypedArray a, int widthAttr,
349                 int heightAttr) {
350
351             if (a.hasValue(widthAttr)) {
352                 width = a.getLayoutDimension(widthAttr, "layout_width");
353             } else {
354                 width = WRAP_CONTENT;
355             }
356
357             if (a.hasValue(heightAttr)) {
358                 height = a.getLayoutDimension(heightAttr, "layout_height");
359             } else {
360                 height = WRAP_CONTENT;
361             }
362         }
363     }
364
365     /**
366      * <p>
367      * Interface definition for a callback to be invoked when the checked radio
368      * button changed in this group.
369      * </p>
370      */
371     public interface OnCheckedChangeListener {
372         /**
373          * <p>
374          * Called when the checked radio button has changed. When the selection
375          * is cleared, checkedId is -1.
376          * </p>
377          *
378          * @param group
379          *            the group in which the checked radio button has changed
380          * @param checkedId
381          *            the unique identifier of the newly checked radio button
382          */
383         public void onCheckedChanged(FlowRadioGroup group, int checkedId);
384     }
385
386     private class CheckedStateTracker implements
387             CompoundButton.OnCheckedChangeListener {
388         public void onCheckedChanged(CompoundButton buttonView,
389                 boolean isChecked) {
390             // prevents from infinite recursion
391             if (mProtectFromCheckedChange) {
392                 return;
393             }
394
395             mProtectFromCheckedChange = true;
396             if (mCheckedId != -1) {
397                 setCheckedStateForView(mCheckedId, false);
398             }
399             mProtectFromCheckedChange = false;
400
401             int id = buttonView.getId();
402             setCheckedId(id);
403         }
404     }
405
406     /**
407      * <p>
408      * A pass-through listener acts upon the events and dispatches them to
409      * another listener. This allows the table layout to set its own internal
410      * hierarchy change listener without preventing the user to setup his.
411      * </p>
412      */
413     private class PassThroughHierarchyChangeListener implements
414             ViewGroup.OnHierarchyChangeListener {
415         private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;
416
417         public void onChildViewAdded(View parent, View child) {
418             if (parent == FlowRadioGroup.this && child instanceof RadioButton) {
419                 int id = child.getId();
420                 // generates an id if it's missing
421                 if (id == View.NO_ID) {
422                     id = child.hashCode();
423                     child.setId(id);
424                 }
425                 ((RadioButton) child)
426                         .setOnCheckedChangeListener(mChildOnCheckedChangeListener);
427             } else if (parent == FlowRadioGroup.this
428                     && child instanceof ViewGroup) {// 如果是复合控件
429                 // 查找并设置id
430                 setCheckedId((ViewGroup) child);
431             }
432
433             if (mOnHierarchyChangeListener != null) {
434                 mOnHierarchyChangeListener.onChildViewAdded(parent, child);
435             }
436         }
437
438         public void onChildViewRemoved(View parent, View child) {
439             if (parent == FlowRadioGroup.this && child instanceof RadioButton) {
440                 ((RadioButton) child).setOnCheckedChangeListener(null);
441             } else if (parent == FlowRadioGroup.this
442                     && child instanceof ViewGroup) {
443                 findRadioButton((ViewGroup) child).setOnCheckedChangeListener(
444                         null);
445             }
446             if (mOnHierarchyChangeListener != null) {
447                 mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
448             }
449         }
450     }
451 }

简单讲解下我的实现:

1)在addview方法中,加上判断,当前子控件是否为viewgroup类型

@Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child instanceof RadioButton) {
            final RadioButton button = (RadioButton) child;
            radioButtons.add(button);//将找到的控件添加到集合中

            if (button.isChecked()) {
                mProtectFromCheckedChange = true;
                if (mCheckedId != -1) {
                    setCheckedStateForView(mCheckedId, false);
                }
                mProtectFromCheckedChange = false;
                setCheckedId(button.getId());
            }
        } else if (child instanceof ViewGroup) {// 如果是复合控件
            // 遍历复合控件
            ViewGroup vg = ((ViewGroup) child);
            setCheckedView(vg);
        }

        super.addView(child, index, params);
    }

    /** 查找复合控件并设置radiobutton */
    private void setCheckedView(ViewGroup vg) {
        int len = vg.getChildCount();
        for (int i = 0; i < len; i++) {
            if (vg.getChildAt(i) instanceof RadioButton) {// 如果找到了,就设置check状态
                final RadioButton button = (RadioButton) vg.getChildAt(i);
                // 添加到容器
                radioButtons.add(button);
                if (button.isChecked()) {
                    mProtectFromCheckedChange = true;
                    if (mCheckedId != -1) {
                        setCheckedStateForView(mCheckedId, false);
                    }
                    mProtectFromCheckedChange = false;
                    setCheckedId(button.getId());
                }
            } else if (vg.getChildAt(i) instanceof ViewGroup) {// 迭代查找并设置
                ViewGroup childVg = (ViewGroup) vg.getChildAt(i);
                setCheckedView(childVg);
            }
        }
    }

2)定义一个数组存放当前所有查到到的radiobutton;

3)在onChildViewAdded方法中,判断新添加的子控件是否为viewgroup类型

1
2
3
4
5
else if (parent
== FlowRadioGroup.
this
                    &&
child 
instanceof ViewGroup)
{
//
如果是复合控件
                //
查找并设置id
                setCheckedId((ViewGroup)
child);
            }

  

/** 查找复合控件并设置id */
    private void setCheckedId(ViewGroup vg) {
        int len = vg.getChildCount();
        for (int i = 0; i < len; i++) {
            if (vg.getChildAt(i) instanceof RadioButton) {// 如果找到了,就设置check状态
                final RadioButton button = (RadioButton) vg.getChildAt(i);
                int id = button.getId();
                // generates an id if it's missing
                if (id == View.NO_ID) {
                    id = button.hashCode();
                    button.setId(id);
                }
                button.setOnCheckedChangeListener(mChildOnCheckedChangeListener);
            } else if (vg.getChildAt(i) instanceof ViewGroup) {// 迭代查找并设置
                ViewGroup childVg = (ViewGroup) vg.getChildAt(i);
                setCheckedId(childVg);
            }
        }
    }

下面是DivisionEditText的源码;

  1 package com.newgame.sdk.view;
  2
  3 import android.content.Context;
  4 import android.text.Editable;
  5 import android.text.TextWatcher;
  6 import android.util.AttributeSet;
  7 import android.view.View;
  8 import android.widget.EditText;
  9
 10 /**
 11  * 分割输入框
 12  *
 13  * @author Administrator
 14  *
 15  */
 16 public class DivisionEditText extends EditText {
 17
 18     /* 每组的长度 */
 19     private Integer eachLength = 4;
 20     /* 分隔符 */
 21     private String delimiter = " ";
 22
 23     private String text = "";
 24
 25     public DivisionEditText(Context context) {
 26         super(context);
 27         init();
 28     }
 29
 30     public DivisionEditText(Context context, AttributeSet attrs) {
 31         super(context, attrs);
 32         init();
 33
 34     }
 35
 36     public DivisionEditText(Context context, AttributeSet attrs, int defStyle) {
 37         super(context, attrs, defStyle);
 38         init();
 39     }
 40
 41     /**
 42      * 初始化
 43      */
 44     public void init() {
 45
 46         // 内容变化监听
 47         this.addTextChangedListener(new DivisionTextWatcher());
 48         // 获取焦点监听
 49         this.setOnFocusChangeListener(new DivisionFocusChangeListener());
 50     }
 51
 52     /**
 53      * 文本监听
 54      *
 55      * @author Administrator
 56      *
 57      */
 58     private class DivisionTextWatcher implements TextWatcher {
 59
 60         @Override
 61         public void afterTextChanged(Editable s) {
 62         }
 63
 64         @Override
 65         public void beforeTextChanged(CharSequence s, int start, int count,
 66                 int after) {
 67         }
 68
 69         @Override
 70         public void onTextChanged(CharSequence s, int start, int before,
 71                 int count) {
 72             // 统计个数
 73             int len = s.length();
 74             if (len < eachLength)// 长度小于要求的数
 75                 return;
 76             if (count > 1) {
 77                 return;
 78             }
 79             // 如果包含空格,就清除
 80             char[] chars = s.toString().replace(" ", "").toCharArray();
 81             len = chars.length;
 82             // 每4个分组,加上空格组合成新的字符串
 83             StringBuffer sb = new StringBuffer();
 84             for (int i = 0; i < len; i++) {
 85                 if (i % eachLength == 0 && i != 0)// 每次遍历到4的倍数,就添加一个空格
 86                 {
 87                     sb.append(" ");
 88                     sb.append(chars[i]);// 添加字符
 89                 } else {
 90                     sb.append(chars[i]);// 添加字符
 91                 }
 92             }
 93             // 设置新的字符到文本
 94             // System.out.println("*************" + sb.toString());
 95             text = sb.toString();
 96             setText(text);
 97             setSelection(text.length());
 98         }
 99     }
100
101     /**
102      * 获取焦点监听
103      *
104      * @author Administrator
105      *
106      */
107     private class DivisionFocusChangeListener implements OnFocusChangeListener {
108
109         @Override
110         public void onFocusChange(View v, boolean hasFocus) {
111             if (hasFocus) {
112                 // 设置焦点
113                 setSelection(getText().toString().length());
114             }
115         }
116     }
117
118     /** 得到每组个数 */
119     public Integer getEachLength() {
120         return eachLength;
121     }
122
123     /** 设置每组个数 */
124     public void setEachLength(Integer eachLength) {
125         this.eachLength = eachLength;
126     }
127
128     /** 得到间隔符 */
129     public String getDelimiter() {
130         return delimiter;
131     }
132
133     /** 设置间隔符 */
134     public void setDelimiter(String delimiter) {
135         this.delimiter = delimiter;
136     }
137
138 }

上面代码实现逻辑:在TextWatcher的onTextChanged方法中判断当前输入的字符,然后没4位添加一个空格,组成新的字符

@Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            // 统计个数
            int len = s.length();
            if (len < eachLength)// 长度小于要求的数
                return;
            if (count > 1) {// 设置新字符串的时候,直接返回
                return;
            }
            // 如果包含空格,就清除
            char[] chars = s.toString().replace(" ", "").toCharArray();
            len = chars.length;
            // 每4个分组,加上空格组合成新的字符串
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < len; i++) {
                if (i % eachLength == 0 && i != 0)// 每次遍历到4的倍数,就添加一个空格
                {
                    sb.append(" ");
                    sb.append(chars[i]);// 添加字符
                } else {
                    sb.append(chars[i]);// 添加字符
                }
            }
            // 设置新的字符到文本
            // System.out.println("*************" + sb.toString());
            text = sb.toString();
            setText(text);
            setSelection(text.length());
        }

还有其他两个自定义控件也在项目中,这里界面没体现出来,我已经放在项目中了;

欢迎大家找出代码中的存在bug!!!!

最后附上代码下载地址:http://www.eoeandroid.com/forum.php?mod=attachment&aid=MTIwMDM1fDM5NTYzZjQ3fDEzOTY0Mjc4NDF8NzU4MzI1fDMyODQyNw%3D%3D

介绍几个好用的android自定义控件的更多相关文章

  1. Android自定义控件之自定义ViewGroup实现标签云

    前言: 前面几篇讲了自定义控件绘制原理Android自定义控件之基本原理(一),自定义属性Android自定义控件之自定义属性(二),自定义组合控件Android自定义控件之自定义组合控件(三),常言 ...

  2. Android自定义控件之自定义组合控件

    前言: 前两篇介绍了自定义控件的基础原理Android自定义控件之基本原理(一).自定义属性Android自定义控件之自定义属性(二).今天重点介绍一下如何通过自定义组合控件来提高布局的复用,降低开发 ...

  3. Android自定义控件之自定义属性

    前言: 上篇介绍了自定义控件的基本要求以及绘制的基本原理,本篇文章主要介绍如何给自定义控件自定义一些属性.本篇文章将继续以上篇文章自定义圆形百分比为例进行讲解.有关原理知识请参考Android自定义控 ...

  4. Android自定义控件之基本原理

    前言: 在日常的Android开发中会经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件,今天先大致了解一下自定义控件的要求和实现的基本原理. 自 ...

  5. Android自定义控件1

    概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...

  6. 一起来学习Android自定义控件1

    概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...

  7. [Xamarin.Android] 自定义控件

    [Xamarin.Android] 自定义控件 前言 软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表.折线图...等等.这时开发人员可以透过自定义控件的方式,为项 ...

  8. android自定义控件实现TextView按下后字体颜色改变

    今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能 直接看图片             第一张是按下后截的图,功能很简单, ...

  9. Android自定义控件:进度条的四种实现方式(Progress Wheel的解析)

    最近一直在学习自定义控件,搜了许多大牛们Blog里分享的小教程,也上GitHub找了一些类似的控件进行学习.发现读起来都不太好懂,就想写这么一篇东西作为学习笔记吧. 一.控件介绍: 进度条在App中非 ...

随机推荐

  1. CF | Alyona and Mex

    Someone gave Alyona an array containing n positive integers a1, a2, ..., an. In one operation, Alyon ...

  2. MySQL where 子句

    MySQL where 子句 我们知道从MySQL表中使用SQL SELECT 语句来读取数据. 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中. 语法 以下是SQL ...

  3. Unity3D各平台Application.xxxPath的路径

    前几天我们游戏在一个同事的Android手机上启动时无法正常进入,经查发现Application.temporaryCachePath和Application.persistentDataPath返回 ...

  4. windows10,redhat6.5下python3.5.2使用cx_Oracle链接oracle

    0.序言 项目主要使用oracle但是我不太喜欢其他编程语言,加上可能需要用python部署算法包,从oracle表中读出数据,处理完成后在放回oracle中去,所以在windows上就想到先用pyt ...

  5. 使用Spring Boot开发Web项目

    前面两篇博客中我们简单介绍了Spring Boot项目的创建.并且也带小伙伴们来DIY了一个Spring Boot自动配置功能,那么这些东西说到底最终还是要回归到Web上才能体现出它的更大的价值,so ...

  6. Android图表库MPAndroidChart(八)——饼状图的扩展:折线饼状图

    Android图表库MPAndroidChart(八)--饼状图的扩展:折线饼状图 我们接着上文,饼状图的扩展,增加折现的说明,来看下我们要实现的效果 因为之前对MPAndroidChart的熟悉,所 ...

  7. win 8.1 64位彻底删除王码98

    安全模式 C:\Windows\SysWOW64\ 删除:winwb98.IME和winwb98.MB 注册表: 找到王码五笔相关的项.一般在最下面的以字母E开头的文件夹.全部删除. HKEY_LOC ...

  8. [Mysql]mysql windows下配置文件

    环境是win7 mysql5.6版本 测试下配置文件是否可用(之前没用过windows下的msyql配置) 修改配置前查询下: mysql> show variables like '%max_ ...

  9. EBS销售(OE)模块常用表

     select * from ra_customers 客户 select * from ra_addresses_all 地址 select * from ra_site_uses_all 用户 ...

  10. OpenMP与MPI联合编程

    研究一下如何一起使用mpi和openmp 先上程序: #include <stdio.h> #include <stdlib.h> #ifdef _OPENMP #includ ...