`

Android自定义ViewGroup View的大小和坐标控制

 
阅读更多
  1. 除非你总是需要一个100×100像素的控件,否则,你必须要重写onMeasure。  
  2.   
  3. onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec。  
  4. 它们指明控件可获得的空间以及关于这个空间描述的元数据。  
  5.   
  6.  比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。  
  7. 接下来的代码片段给出了如何重写onMeasure。注意,调用的本地空方法是来计算高度和宽度的。它们会译解widthHeightSpec和heightMeasureSpec值,并计算出合适的高度和宽度值。  
  8.   
  9.    
  10.   
  11. @Override  
  12.   
  13. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  14.   
  15. int measuredHeight = measureHeight(heightMeasureSpec);  
  16.   
  17. int measuredWidth = measureWidth(widthMeasureSpec);  
  18.   
  19. setMeasuredDimension(measuredHeight, measuredWidth);  
  20.   
  21. }  
  22.   
  23.    
  24.   
  25. private int measureHeight(int measureSpec) {  
  26.   
  27. // Return measured widget height.   
  28.   
  29. }  
  30.   
  31.    
  32.   
  33. private int measureWidth(int measureSpec) {  
  34.   
  35. // Return measured widget width.   
  36.   
  37. }  
  38.   
  39.    
  40.   
  41. 边界参数——widthMeasureSpec和heightMeasureSpec ,效率的原因以整数的方式传入。在它们使用之前,首先要做的是使用MeasureSpec类的静态方法getMode和getSize来译解,如下面的片段所示:  
  42.   
  43.    
  44.   
  45. int specMode = MeasureSpec.getMode(measureSpec);  
  46.   
  47. int specSize = MeasureSpec.getSize(measureSpec);  
  48.   
  49.    
  50.   
  51. 依据specMode的值,如果是AT_MOST,specSize 代表的是最大可获得的空间;如果是EXACTLY,specSize 代表的是精确的尺寸;如果是UNSPECIFIED,对于控件尺寸来说,没有任何参考意义。  
  52.   
  53. 当以EXACT方式标记测量尺寸,父元素会坚持在一个指定的精确尺寸区域放置View。在父元素问子元素要多大空间时,AT_MOST指示者会说给我最大的范围。在很多情况下,你得到的值都是相同的。  
  54.   
  55. 在两种情况下,你必须绝对的处理这些限制。在一些情况下,它可能会返回超出这些限制的尺寸,在这种情况下,你可以让父元素选择如何对待超出的View,使用裁剪还是滚动等技术。  
  56.   
  57.  接下来的框架代码给出了处理View测量的典型实现:  
  58.   
  59.    
  60.   
  61. @Override  
  62.   
  63. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  64.   
  65. int measuredHeight = measureHeight(heightMeasureSpec);  
  66.   
  67. int measuredWidth = measureWidth(widthMeasureSpec);  
  68.   
  69. setMeasuredDimension(measuredHeight, measuredWidth);  
  70.   
  71. }  
  72.   
  73.    
  74.   
  75. private int measureHeight(int measureSpec) {  
  76.   
  77. int specMode = MeasureSpec.getMode(measureSpec);  
  78.   
  79. int specSize = MeasureSpec.getSize(measureSpec);  
  80.   
  81.    
  82.   
  83. // Default size if no limits are specified.   
  84.   
  85. int result = 500;  
  86.   
  87. if (specMode == MeasureSpec.AT_MOST)   
  88.   
  89. {  
  90.   
  91. // Calculate the ideal size of your   
  92.   
  93. // control within this maximum size.   
  94.   
  95. // If your control fills the available   
  96.   
  97. // space return the outer bound.   
  98.   
  99. result = specSize;  
  100.   
  101. }   
  102.   
  103. else if (specMode == MeasureSpec.EXACTLY)   
  104.   
  105. {  
  106.   
  107. // If your control can fit within these bounds return that value.   
  108.   
  109. result = specSize;  
  110.   
  111. }  
  112.   
  113. return result;  
  114.   
  115. }  
  116.   
  117.    
  118.   
  119. private int measureWidth(int measureSpec) {  
  120.   
  121. int specMode = MeasureSpec.getMode(measureSpec);  
  122.   
  123. int specSize = MeasureSpec.getSize(measureSpec);  
  124.   
  125.    
  126.   
  127. // Default size if no limits are specified.   
  128.   
  129. int result = 500;  
  130.   
  131. if (specMode == MeasureSpec.AT_MOST)  
  132.   
  133. {  
  134.   
  135. // Calculate the ideal size of your control   
  136.   
  137. // within this maximum size.   
  138.   
  139. // If your control fills the available space   
  140.   
  141. // return the outer bound.   
  142.   
  143. result = specSize;  
  144.   
  145. }   
  146.   
  147. else if (specMode == MeasureSpec.EXACTLY)   
  148.   
  149. {  
  150.   
  151. // If your control can fit within these bounds return that value.   
  152.   
  153. result = specSize;  
  154.   
  155. }  
  156.   
  157. return result;  
  158.   
  159. }  
  160.   
  161.    
除非你总是需要一个100×100像素的控件,否则,你必须要重写onMeasure。

onMeasure方法在控件的父元素正要放置它的子控件时调用。它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec。
它们指明控件可获得的空间以及关于这个空间描述的元数据。

 比返回一个结果要好的方法是你传递View的高度和宽度到setMeasuredDimension方法里。
接下来的代码片段给出了如何重写onMeasure。注意,调用的本地空方法是来计算高度和宽度的。它们会译解widthHeightSpec和heightMeasureSpec值,并计算出合适的高度和宽度值。

 

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int measuredHeight = measureHeight(heightMeasureSpec);

int measuredWidth = measureWidth(widthMeasureSpec);

setMeasuredDimension(measuredHeight, measuredWidth);

}

 

private int measureHeight(int measureSpec) {

// Return measured widget height.

}

 

private int measureWidth(int measureSpec) {

// Return measured widget width.

}

 

边界参数——widthMeasureSpec和heightMeasureSpec ,效率的原因以整数的方式传入。在它们使用之前,首先要做的是使用MeasureSpec类的静态方法getMode和getSize来译解,如下面的片段所示:

 

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

依据specMode的值,如果是AT_MOST,specSize 代表的是最大可获得的空间;如果是EXACTLY,specSize 代表的是精确的尺寸;如果是UNSPECIFIED,对于控件尺寸来说,没有任何参考意义。

当以EXACT方式标记测量尺寸,父元素会坚持在一个指定的精确尺寸区域放置View。在父元素问子元素要多大空间时,AT_MOST指示者会说给我最大的范围。在很多情况下,你得到的值都是相同的。

在两种情况下,你必须绝对的处理这些限制。在一些情况下,它可能会返回超出这些限制的尺寸,在这种情况下,你可以让父元素选择如何对待超出的View,使用裁剪还是滚动等技术。

 接下来的框架代码给出了处理View测量的典型实现:

 

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int measuredHeight = measureHeight(heightMeasureSpec);

int measuredWidth = measureWidth(widthMeasureSpec);

setMeasuredDimension(measuredHeight, measuredWidth);

}

 

private int measureHeight(int measureSpec) {

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

// Default size if no limits are specified.

int result = 500;

if (specMode == MeasureSpec.AT_MOST) 

{

// Calculate the ideal size of your

// control within this maximum size.

// If your control fills the available

// space return the outer bound.

result = specSize;

} 

else if (specMode == MeasureSpec.EXACTLY) 

{

// If your control can fit within these bounds return that value.

result = specSize;

}

return result;

}

 

private int measureWidth(int measureSpec) {

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

 

// Default size if no limits are specified.

int result = 500;

if (specMode == MeasureSpec.AT_MOST)

{

// Calculate the ideal size of your control

// within this maximum size.

// If your control fills the available space

// return the outer bound.

result = specSize;

} 

else if (specMode == MeasureSpec.EXACTLY) 

{

// If your control can fit within these bounds return that value.

result = specSize;

}

return result;

}

 

 

 

getWidth得到是某个view的实际尺寸.

getMeasuredWidth是得到某view想要在parent view里面占的大小.

 

  1. getWidth在OnCreat的时候得到的是0. 当一个view对象创建时,android并不知道其大小,所以getWidth()和   getHeight()返回的结果是0,真正大小是在计算布局时才会计算.

    2.  getMeasuredWidth必须在parent view或者它自己调用measure()函数之后才能得到. measure函数就是计算该函数需要占用的空间大小.

 

    3.onMeasure会在onLayout之前调用

     4.如果ViewGroup中的View通过动画移动了位置 需要调用requestLayout()重新定位View的位置;
 
 
     viewgroup简单说就是可以装view的view.今天遇到一个问题,就是需要一个可以自动根据一行中view的宽度自动换行的布局,网上找了下,没有相关的例子,但是找到了思路:自定义一个viewgroup,然后在onlayout文件里面自动检测view的右边缘的横坐标值,和你的view的parent view的况度判断是否换行显示view就可以了。因为代码比较简单,就不多说了:

  

复制代码
 1 public class MyViewGroup extends ViewGroup {
 2     private final static String TAG = "MyViewGroup";
 3     
 4     private final static int VIEW_MARGIN=2;
 5 
 6     public MyViewGroup(Context context) {
 7         super(context);
 8     }
 9     @Override
10     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
11         Log.d(TAG, "widthMeasureSpec = "+widthMeasureSpec+" heightMeasureSpec"+heightMeasureSpec);
12         
13         for (int index = 0; index < getChildCount(); index++) {
14             final View child = getChildAt(index);
15             // measure16             child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
17         }
18 
19         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
20     }
21 
22     @Override
23     protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
24         Log.d(TAG, "changed = "+arg0+" left = "+arg1+" top = "+arg2+" right = "+arg3+" botom = "+arg4);
25         final int count = getChildCount();
26         int row=0;// which row lay you view relative to parent27         int lengthX=arg1;    // right position of child relative to parent28         int lengthY=arg2;    // bottom position of child relative to parent29         for(int i=0;i<count;i++){
30             
31             final View child = this.getChildAt(i);
32             int width = child.getMeasuredWidth();
33             int height = child.getMeasuredHeight();
34             lengthX+=width+VIEW_MARGIN;
35             lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2;
36             //if it can't drawing on a same line , skip to next line37             if(lengthX>arg3){
38                 lengthX=width+VIEW_MARGIN+arg1;
39                 row++;
40                 lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2;
41                 
42             }
43             
44             child.layout(lengthX-width, lengthY-height, lengthX, lengthY);
45         }
46 
47     }
48 
49 }
复制代码

  这里有个地方要注意,那就要明白ViewGroup的绘图流程:ViewGroup绘制包括两个步骤:1.measure 2.layout

  在两个步骤中分别调用回调函数:1.onMeasure()   2.onLayout()

  1.onMeasure() 在这个函数中,ViewGroup会接受childView的请求的大小,然后通过childView的 measure(newWidthMeasureSpec, heightMeasureSpec)函数存储到childView中,以便childView的getMeasuredWidth() andgetMeasuredHeight() 的值可以被后续工作得到。

  2.onLayout() 在这个函数中,ViewGroup会拿到childView的getMeasuredWidth() andgetMeasuredHeight(),用来布局所有的childView。

  3.View.MeasureSpec 与 LayoutParams 这两个类,是ViewGroup与childView协商大小用的。其中,View.MeasureSpec是ViewGroup用来部署 childView用的, LayoutParams是childView告诉ViewGroup 我需要多大的地方。

  4.在View 的onMeasure的最后要调用setMeasuredDimension()这个方法存储View的大小,这个方法决定了当前View的大小。

  

  效果图:

                                 

 

 

我们都知道在onCreate()里面获取控件的高度是0,这是为什么呢?我们来看一下示例:
首先我们自己写一个控件,这个控件非常简单:
[java]
public class MyImageView extends ImageView { 
 
    public MyImageView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
    } 
    public MyImageView(Context context) { 
        super(context); 
    } 
     
    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
        System.out.println("onMeasure 我被调用了"+System.currentTimeMillis()); 
    } 
     
    @Override 
    protected void onDraw(Canvas canvas) { 
        super.onDraw(canvas); 
        System.out.println("onDraw 我被调用了"+System.currentTimeMillis()); 
    } 
 

布局文件:
[java] 
<com.test.MyImageView 
    android:id="@+id/imageview" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:src="@drawable/test" /> 

测试的Activity的onCreate():
[java] 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main);         
    System.out.println("执行完毕.."+System.currentTimeMillis()); 

现在我们现在来看一下结果:

说明等onCreate方法执行完了,我们定义的控件才会被度量(measure),所以我们在onCreate方法里面通过view.getHeight()获取控件的高度或者宽度肯定是0,因为它自己还没有被度量,也就是说他自己都不知道自己有多高,而你这时候去获取它的尺寸,肯定是不行的.

现在碰到这个问题我们不能不解决,在网上找到了如下办法:
[java] 
//------------------------------------------------方法一 
int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
imageView.measure(w, h); 
int height =imageView.getMeasuredHeight(); 
int width =imageView.getMeasuredWidth(); 
textView.append("\n"+height+","+width); 
 
 
 
 
//-----------------------------------------------方法二 
ViewTreeObserver vto = imageView.getViewTreeObserver(); 
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
    public boolean onPreDraw() { 
        int height = imageView.getMeasuredHeight(); 
        int width = imageView.getMeasuredWidth(); 
        textView.append("\n"+height+","+width); 
        return true; 
    } 
}); 
//-----------------------------------------------方法三    
ViewTreeObserver vto2 = imageView.getViewTreeObserver();   
vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
    @Override   
    public void onGlobalLayout() { 
        imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);   
        textView.append("\n\n"+imageView.getHeight()+","+imageView.getWidth()); 
    }   
});   

这三个方法是哪里找到现在已经忘了.

现在要讨论的是当我们需要时候使用哪个方法呢?
现在把测试的Activity改成如下:
[java] 
@Override 
  public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.main); 
      final ImageView imageView = (ImageView) findViewById(R.id.imageview);       
       
      //------------------------------------------------方法一 
      int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
      int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED); 
      imageView.measure(w, h); 
      int height =imageView.getMeasuredHeight(); 
      int width =imageView.getMeasuredWidth(); 
      textView.append("\n"+height+","+width); 
       
      System.out.println("执行完毕.."+System.currentTimeMillis()); 
  } 

 

接着来看下面几种方式输出结果:
把测试Activity改成如下:
[java] 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    final ImageView imageView = (ImageView) findViewById(R.id.imageview); 
-----------------------------------------------方法二 
    ViewTreeObserver vto = imageView.getViewTreeObserver(); 
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
        public boolean onPreDraw() { 
            int height = imageView.getMeasuredHeight(); 
            int width = imageView.getMeasuredWidth(); 
            textView.append("\n"+height+","+width); 
            return true; 
        } 
    }); 

结果如下:


方法三就不再测试了同方法二!!!

那么方法而和方法三在执行上有什么区别呢?
我们在布局文件中加入一个TextView来记录这个控件的宽高.
[java] 
<ScrollView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" > 
 
    <TextView 
        android:id="@+id/text" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" /> 
</ScrollView> 

先来测试方法而:
[java] 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    final ImageView imageView = (ImageView) findViewById(R.id.imageview); 
-----------------------------------------------方法二 
    ViewTreeObserver vto = imageView.getViewTreeObserver(); 
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
        public boolean onPreDraw() { 
            int height = imageView.getMeasuredHeight(); 
            int width = imageView.getMeasuredWidth(); 
            textView.append("\n"+height+","+width); 
            return true; 
        } 
    }); 

结果如下:


我们再来测试方法三
[java] 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 
    final ImageView imageView = (ImageView) findViewById(R.id.imageview); 
    //-----------------------------------------------方法三    
    ViewTreeObserver vto2 = imageView.getViewTreeObserver();   
    vto2.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 
        @Override   
        public void onGlobalLayout() { 
            imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);   
            textView.append("\n\n"+imageView.getHeight()+","+imageView.getWidth()); 
        }   
    });   

输出结果如下:


我想这方法二和方法三之间的区别就不用说了吧.
  总结:那么需要获取控件的宽高该用那个方法呢?
方法一: 比其他的两个方法多了一次计算,也就是多调用了一次onMeasure()方法,该方法虽然看上去简单,但是如果要目标控件计算耗时比较大的话,不见时使用,如listView等.
方法二,它的回调方法会调用很多次,并且滑动TextView的时候任然会调用,所以不建议使用.
方法三,比较合适.
当然,实际应用的时候需要根据实际情况而定.

分享到:
评论

相关推荐

    Android自定义ViewGroup(一)

    这篇博客文章“Android自定义ViewGroup(一)”详细介绍了如何从零开始创建一个自定义的ViewGroup,以及在这个过程中可能遇到的问题和解决策略。下面将深入探讨这个主题。 首先,我们来了解ViewGroup的基本概念。...

    自定义ViewGroup实现瀑布流

    瀑布流布局,也被称为...但总体来说,自定义ViewGroup实现瀑布流需要理解Android布局系统,熟悉测量和布局过程,以及掌握图片加载和内存管理策略。在实际项目中,这将是一个锻炼和提升Android开发技能的好机会。

    Android 自定义ViewGroup 实战篇 -> 实现FlowLayout源码程序

    在Android开发中,自定义ViewGroup是实现复杂布局和交互的关键技术之一。本实战篇将聚焦于如何实现一个名为FlowLayout的自定义布局,它允许子视图按行排列,类似于HTML中的`&lt;div&gt;`标签。在Android应用设计中,...

    Android中使用自定义ViewGroup的总结

    本文将对如何在Android中创建和使用自定义ViewGroup进行总结,并提供一个具体的实例来演示如何为Child View设置属性。 首先,我们要了解自定义ViewGroup的两大类别: 1. 创建全新的ViewGroup类型:这通常涉及构建...

    Android自定义ViewGroup之FlowLayout(三)

    在Android开发中,自定义ViewGroup是实现特定布局需求的重要手段。本文主要讲解如何自定义一个FlowLayout,这种布局方式能够适应各种需要动态排列元素的场景,例如关键字标签和搜索热词列表。在Android SDK中并未...

    实现侧滑上下滑自定义ViewGroup

    在Android开发中,自定义ViewGroup是实现复杂交互和界面设计的重要手段,它允许开发者根据需求定制特定的布局和交互行为。"实现侧滑上下滑自定义ViewGroup"的主题涉及了Android开发中的几个核心概念,包括自定义View...

    自定义ViewGroup 显示两个TextView

    在Android开发中,自定义ViewGroup是实现复杂布局和交互的关键技术之一。本文将深入探讨如何创建一个自定义的ViewGroup,并在其内部显示两个TextView。我们将详细讲解自定义ViewGroup的过程,包括布局设计、测量、...

    Android 自定义ViewGroup之实现FlowLayout-标签流容器

    自定义ViewGroup时,我们通常会继承自`android.view.ViewGroup`,并重写几个关键方法,如`onMeasure()`、`onLayout()`和`onDraw()`。 在FlowLayout的实现中,`onMeasure()`方法用来测量每个子视图的大小,并确定...

    Android自定义ViewGroup

    总之,Android自定义ViewGroup是实现独特布局和交互的关键,通过重写测量、布局和触摸事件处理方法,我们可以创建出满足各种需求的自定义视图组件。结合滑动功能,可以让用户界面更加生动和互动。通过对`...

    android自定义View-手绘地图

    总结,本项目“android自定义View-手绘地图”涵盖了Android自定义组件的核心技术,包括自定义View和自定义ViewGroup的使用,通过它们可以构建出一个可定制、可交互的地图视图。开发者可以根据实际需求调整绘制逻辑,...

    android自定义View(五)打造自己的遥控器菜单

    这个过程涉及到了Android自定义View的基本原理,包括绘图、触摸事件处理、动画和布局管理等。了解并掌握这些知识,对于提升Android应用的用户体验具有重要意义。想要了解更多关于Android自定义View的内容,可以访问...

    自定义ViewGroup(ZhyCustomViewgroup02)

    在Android开发中,自定义ViewGroup是实现复杂布局和交互效果的重要手段。`ZhyCustomViewgroup02`项目很可能是某位开发者分享的一个关于自定义ViewGroup的示例,适用于Android Studio。在这个项目中,我们可以学习到...

    自定义viewgroup

    在Android开发中,自定义ViewGroup是实现复杂布局和交互效果的重要手段。它允许开发者根据需求创建具有独特功能和外观的视图容器。本篇将深入探讨如何利用谷歌官方的自定义ViewGroup实例来理解这一关键概念。 首先...

    Android自定义View的事件分发机制(一)

    总之,理解并掌握Android自定义View的事件分发机制对于优化用户界面和提升应用交互体验至关重要。开发者需要熟练运用 `dispatchTouchEvent()`, `onInterceptTouchEvent()`, 和 `onTouchEvent()` 这些方法,以及了解...

    android 自定义view2

    在自定义ViewGroup时,我们需要重写`onMeasure()`方法来确定子View的大小。这个方法需要调用`measureChild()`或`measureChildren()`方法,对每个子View进行测量,并设置合适的尺寸。同时,要调用`...

    自定义ViewGroup仿ViewPager

    在Android开发中,自定义ViewGroup是实现个性化界面和复杂交互的重要手段。"自定义ViewGroup仿ViewPager"这个主题涉及到滚动机制,包括`scrollTo`、`scrollBy`以及`Scroller`这三个关键知识点,这些都是Android视图...

    Android中自定义View

    自定义View首先要创建一个新的Java类,继承自Android提供的View或ViewGroup类。常见的基类选择有View(用于单个UI元素)和LinearLayout、RelativeLayout等(用于容器,管理多个子视图)。在新类中,我们通常需要重写...

    Android自定义View仿腾讯TIM下拉刷新View

    通过这个项目,开发者不仅可以学习到自定义View的技巧,还能深入理解Android图形绘制和动画系统的工作原理,这对于提升Android开发能力非常有帮助。同时,这也是一个有趣的实践,能够锻炼开发者解决问题和创新设计的...

    自定义ViewGroup

    在Android开发中,自定义ViewGroup是一个非常重要的技能,它涉及到UI组件的底层实现和性能优化。本案例将深入解析自定义ViewGroup的过程,帮助开发者理解与自定义View的区别,并提供实践操作的经验。 首先,我们要...

    自定义ViewGroup滑动

    在Android开发中,自定义ViewGroup是实现复杂布局和交互效果的重要手段。本主题将深入探讨如何通过自定义ViewGroup来实现类似ViewPager的滑动效果。ViewPager是一个强大的组件,它允许用户通过左右滑动来浏览多个...

Global site tag (gtag.js) - Google Analytics