Android源码系列之深入理解ImageView的ScaleType属性

做Android开发的童靴们肯定对系统自带的控件使用的都非常熟悉,比如Button、TextView、ImageView等。如果你问我具体使用,我会给说:拿ImageView来说吧,首先创建一个新的项目,在项目布局文件中应用ImageView控件,代码如下:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#bbaacc" > <ImageView android:src="@drawable/ic_launcher" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#aabbcc" /> </LinearLayout>

上边布局文件为了便于查看各种属性效果,故意加了两个背景颜色,这对我们今天的源码分析影响不大。接着运行一下代码,效果图如下:

恩,不错,运行结果正如所愿,屏幕上显示的正是我们设置的图片,这时候心中不由欣喜ImageView的使用就是这样简单,so easy嘛!呵呵,如果真是这么想那就大错特错了,上边的示例仅仅是在布局文件中使用了ImageView的src,layout_width和layout_height这三个属性罢了,它其他的重要属性我们还没有用到,今天这篇文章就是主要结合源码讲解ImageView的另一个重要的属性------ScaleType,其他的一些属性等将来需要的话再做详细解说。好了,现在正式进入主题。
        ScaleType属性主要是用来定义图片(Bitmap)如何在ImageView中展示的,姑且就认为是展示吧,系统给我们提供了8种可选属性:matrix、fitXY、fitStart、fitCenter、fitEnd、center、centerCrop和centerInside。每一种属性对应的展示效果是不一样的,下面我们先来做一个实验来说明每一种属性的显示效果,我从之前的项目中挑选了两张图片,一张图片的实际尺寸是720*1152,另一张是我把第一张图翻转放缩得到的,它的实际尺寸是96*60,之所以采用两张图片是为了便于对比和观察结果,原图片如下:

OK,测试图片准备好了,接下来我们在布局文件中分别使用ScaleType的每一个属性值,我们开始写布局文件,内容如下:

<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#bbccaa" > <TableLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:text="图片尺寸的宽和高都远远大于ImageView的尺寸" /> <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:layout_width="300px" android:layout_height="300px" android:background="#aabbcc" android:scaleType="matrix" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="fitXY" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="fitStart" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="fitCenter" android:src="@drawable/test" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" > <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="matrix" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="fitXY" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="fitStart" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="fitCenter" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" > <ImageView android:layout_width="300px" android:layout_height="300px" android:background="#aabbcc" android:scaleType="fitEnd" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="center" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="centerCrop" android:src="@drawable/test" /> <ImageView android:layout_width="300px" android:layout_height="300px" android:layout_marginLeft="10dp" android:background="#aabbcc" android:scaleType="centerInside" android:src="@drawable/test" /> </TableRow> <TableRow android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" > <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="fitEnd" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="center" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="centerCrop" /> <TextView android:layout_width="300px" android:layout_height="wrap_content" android:gravity="center" android:text="centerInside" /> </TableRow> </TableLayout> </ScrollView>

为了快速进入今天文章主题,布局文件并没有按照平时开发中所遵循的Android开发规范来写。布局中使用的是TableLayout标签嵌套TableRow的方式,分成两行,每一行是4列,恰好8种属性可以合理对比查看。当然了这里有更高效的写法来实现同样的效果,比如使用RelativeLayout布局等。
        在布局文件中我们定义了每个ImageView的宽高都是固定的300像素,这个尺寸远小于或者是远大于测试的图片尺寸,另外为了便于观察效果我给每个ImageView的背景都设置了颜色,接着运行大图和小图的测试结果,效果如下:

通过上述实验结果对比,就可以得出部分属性的展示效果。比如fitXY属性,当ImageView的属性设置成了fitXY时,图片的宽和高就会相应的拉伸或者是压缩来填充满整个ImageView,注意这种拉放缩不成比例。当ImageView的属性设置成了matrix时,如果图片宽高大于ImageView的宽高时,图片的显示就是从ImageView的左上角开始平铺,超出部分不再显示;如果图片宽高小于ImageView的宽高时,图片的显示也是从ImageView的左上角开始平铺,缺少部分空白显示出来或者是显示ImageView的背景。以上仅仅是根据运行结果来得出的结果,权威结论还要通过查看源码来得出,本文分析的源码是Android2.2版本。
        分析ImageView的源码首先从它的构造方法开始,看一下构造方法里边都做了什么工作。构造方法如下:

public ImageView(Context context) { super(context); initImageView(); } public ImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initImageView(); TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ImageView, defStyle, 0); Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src); if (d != null) { setImageDrawable(d); } ////////////////////////////////////////////////// // // 以下源码部分属性初始化不涉及主核心,不再贴出 // ////////////////////////////////////////////////// a.recycle(); //need inflate syntax/reader for matrix }

通过查看构造方法发现,在三个构造方法中都调用了initImageView()这个方法,这个方法是干嘛使的,我们稍后在看。其次是根据在布局文件中定义的属性来初始化相关属性,在测试布局中我们仅仅是用了ImageView的src,layout_width,layout_height和scaleType属性(background属性暂时忽略)。那也就是说在构造函数的初始化中就是对相关属性进行了赋值操作,通过解析src属性我们获取到了一个Drawable的实例对象d,如果d是非空的话就把d作为参数又调用了setImageDrawable(d)函数,我们看看一下这个函数主要做了什么工作,源码如下:

/** * Sets a drawable as the content of this ImageView. * * @param drawable The drawable to set */ public void setImageDrawable(Drawable drawable) { if (mDrawable != drawable) { mResource = 0; mUri = null; int oldWidth = mDrawableWidth; int oldHeight = mDrawableHeight; updateDrawable(drawable); if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) { requestLayout(); } invalidate(); } }

此方法类型是public的,目的是干嘛使的不再解释了,注释上说的是把给定的drawable作为当前ImageView的展示内容,接着是个条件判断,在刚刚完成初始化的时候mDrawable属性还没有被赋值此时为空,因此判断成立程序进入条件语句继续执行,在这里把属性mResource和mUri归零操作并计入mDrawableWidth和mDrawableHeight的初始值,紧接着把传递进来的drawable参数传递给了updateDrawable()方法,那我们继续跟进updateDrawable()看看这里边又做了什么操作,源码如下:

private void updateDrawable(Drawable d) { if (mDrawable != null) { mDrawable.setCallback(null); unscheduleDrawable(mDrawable); } mDrawable = d; if (d != null) { d.setCallback(this); if (d.isStateful()) { d.setState(getDrawableState()); } d.setLevel(mLevel); mDrawableWidth = d.getIntrinsicWidth(); mDrawableHeight = d.getIntrinsicHeight(); applyColorMod(); configureBounds(); } else { mDrawableWidth = mDrawableHeight = -1; } }

该方法首先进行了非空判断,此时mDrawable的值依然是空,所以条件判断不成立跳过此部分,紧接着把传递进来的非空参数d的字赋值给了属性mDrawable,到这里mDrawable才算是完成了赋值操作。然后又进行了条件判断,并设置d的callback为当前ImageView(因为ImageView的父类View实现了Drawable的Callback接口)接下来又把图片的宽和高分别赋值给了mDrawableWidth和mDrawableHeight,紧接着又调用了applyColorMod()方法,当我们没有给ImageView设置透明度或者是颜色过滤器时该方法不会执行。然后调用configureBounds()方法,此方法是我们今天要讲的和ScaleType属性息息相关的重点,不耽误时间了赶紧瞅一下源码吧,(*^__^*) 嘻嘻……

private void configureBounds() { if (mDrawable == null || !mHaveFrame) { return; } int dwidth = mDrawableWidth; int dheight = mDrawableHeight; int vwidth = getWidth() - mPaddingLeft - mPaddingRight; int vheight = getHeight() - mPaddingTop - mPaddingBottom; boolean fits = (dwidth < 0 || vwidth == dwidth) && (dheight < 0 || vheight == dheight); ////////////////////////////////////////代码块一//////////////////////////////////////// if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) { /* If the drawable has no intrinsic size, or we're told to scaletofit, then we just fill our entire view. */ mDrawable.setBounds(0, 0, vwidth, vheight); mDrawMatrix = null; ////////////////////////////////////////代码块二//////////////////////////////////////// } else { // We need to do the scaling ourself, so have the drawable // use its native size. mDrawable.setBounds(0, 0, dwidth, dheight); if (ScaleType.MATRIX == mScaleType) { // Use the specified matrix as-is. if (mMatrix.isIdentity()) { mDrawMatrix = null; } else { mDrawMatrix = mMatrix; } ////////////////////////////////////////代码块三//////////////////////////////////////// } else if (fits) { // The bitmap fits exactly, no transform needed. mDrawMatrix = null; ////////////////////////////////////////代码块四//////////////////////////////////////// } else if (ScaleType.CENTER == mScaleType) { // Center bitmap in view, no scaling. mDrawMatrix = mMatrix; mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f), (int) ((vheight - dheight) * 0.5f + 0.5f)); ////////////////////////////////////////代码块五//////////////////////////////////////// } else if (ScaleType.CENTER_CROP == mScaleType) { mDrawMatrix = mMatrix; float scale; float dx = 0, dy = 0; if (dwidth * vheight > vwidth * dheight) { scale = (float) vheight / (float) dheight; dx = (vwidth - dwidth * scale) * 0.5f; } else { scale = (float) vwidth / (float) dwidth; dy = (vheight - dheight * scale) * 0.5f; } mDrawMatrix.setScale(scale, scale); mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f)); ////////////////////////////////////////代码块六//////////////////////////////////////// } else if (ScaleType.CENTER_INSIDE == mScaleType) { mDrawMatrix = mMatrix; float scale; float dx; float dy; if (dwidth <= vwidth && dheight <= vheight) { scale = 1.0f; } else { scale = Math.min((float) vwidth / (float) dwidth, (float) vheight / (float) dheight); } dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f); dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); mDrawMatrix.setScale(scale, scale); mDrawMatrix.postTranslate(dx, dy); ////////////////////////////////////////代码块七//////////////////////////////////////// } else { // Generate the required transform. mTempSrc.set(0, 0, dwidth, dheight); mTempDst.set(0, 0, vwidth, vheight); mDrawMatrix = mMatrix; mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType)); ////////////////////////////////////////代码块八//////////////////////////////////////// } } }

configureBoundd()函数比较长,为了方便分析源码,我把该函数代码分成了8小块,每一个小块都是一个单独的逻辑。每一块的详解如下:
代码块一:
        该模块代码首先做了一个条件判断,如果当前mDrawable为空或者是mHaveFrame为false则函数直接返回不再往下执行,由于后边的逻辑主要是根据ScaleType属性的类型来判断图片的展示方式,所以再后来这个函数肯定是能往下走的通的,由于篇幅的原因不再深入讲解该函数的调用时机,我会在之后的文章中专门根据源码讲解一下Android系统下View的绘制流程,在之后的绘制流程中会提到configureBounds()的调用时机。该代码块的逻辑是获取图片的宽高存储在dwidth,dheight中,然后又获取到了ImageView的显示图片区域的宽高存放在vwidth和vheight中。然后定义了一个boolean类型的变量,该变量若为true就表示不需要对图片进行放缩处理。
代码块二:
        该代码块的逻辑是当获取到的图片尺寸的宽高未知或者是ImageView的ScaleType属性为FIT_XY时,将mDrawable的显示边界设置成控件ImageView的显示区域大小,并且把mDrawMatrix对象设置成null。需要说明的是setBounds方法用来设置Drawable的绘制区域的,最终在ImageView的onDraw方法中把mDrawable表示的图片绘制到ImageView上。
代码块三:
        如果图片宽高不为0并且ImageView的ScaleType属性不是FIT_XY时,就会把mDrawable的绘制区域设置成图片的原始大小。接着进行判断ImageView的ScaleType属性值是否是MATRIX,如果是MATRIX类型,就会把当前mMatrix赋值给mDrawMatrix。
代码块四:
        代码块四是一个if(fits)的判断,如果fits的值为true,就表示图片大小等于ImageView的大小,不需要对图片进行放缩处理了。
代码块五:
       当mScaleType的类型为CENTER时,实际是将图片进行移位操作,直接点说就是把图片的中心点移动到ImageView的中心点,如果图片的宽高大于ImageView的宽高此时只显示ImageView所包含的部分,大于ImageView的部分不再显示。
      【注意:CENTER属性只对图片进行移动操作而不会进行放缩操作】。
代码块六:
        代码块六是当mScaleType==CENTER_CROP时,进行了一个条件判断:if(dwidth *vheight >vwidth *dheight),看到这句代码的时候我并没有理解其含义,然后我把这句代码转换了一下写法:if(dwidth / vwidth > dheight / vheight),通过这种转换写法然后再看就比较明白了,主要是用来判断宽高比的,就是说用来判断是图片的宽比较接近ImageView控件的宽还是图片的高比较接近ImageView控件的高。如果是图片的高比较接近ImageView的高,通过计算获取需要放缩的scale的值,再计算出需要对图片的宽进行移动的值,最后通过对mDrawMatrix属性进行设置放缩和移动来达到控制图片进行放缩和移动的效果,同样的逻辑处理了当图片的宽比较接近ImageView的宽的情况。从代码可以总结CENTER_CROP属性的特点是:对图片的宽高进行放缩处理,使一边达到ImageView控件的宽高,另一边进行进行移动居中显示若超出则不再显示。
代码块七:
        代码块七是当mScaleType==CENTER_INSIDE时,首先判断图片宽高是否小于ImageView宽高,如果图片宽高小于ImageView的宽高,则scale=1.0f,也就是说不对图片进行放缩处理而是直接移动图片进行居中显示,否则通过Math.min((float)vwidth / (float)dwidth, (float) vheight / (float)dheight);计算出需要对图片进行的放缩值,然后放缩图片宽高并对图片移动居中显示。从代码可以总结CENTER_INSIDE的特点是:控制图片尺寸,对图片宽高进行压缩处理,根据图片和控件的宽高比拿最大的一边进行压缩使之同控件一边相同,另一边小于控件。
代码块八:
        代码块八是对mScaleType为FIT_CENTER,FIT_START,FIT_END的情况下统一做了处理,先设置mTempSrc和mTempDst的边界后,通过调用mDrawMatrix的setRectToRect()方法来对图片进行放缩和移动操作,使图片最大边始终等于ImageView相应的边。结合代码和代码测试结果可以得出如下结论:
        当图片的高大于宽时:
1.当mScaleType == FIT_START时,对图片进行等比放缩,使图片的高与ImageView的高相等,移动图片使之左对齐。
2.当mScaleType == FIT_CENTER时,对图片进行等比放缩,使图片的高与ImageView的高相等,移动图片使之居中对齐。
3.当mScaleType == FIT_END时,对图片进行等比放缩,使图片的高与ImageView的高相等,移动图片使之右对齐。
        当图片的宽大于高时:
1.当mScaleType == FIT_START时,对图片进行等比放缩,使图片的宽与ImageView的宽相等,移动图片使之上对齐。
2.当mScaleType == FIT_CENTER时,对图片进行等比放缩,使图片的宽与ImageView的宽相等,移动图片使之居中对齐。
3.当mScaleType == FIT_END时,对图片进行等比放缩,使图片的宽与ImageView的宽相等,移动图片使之下对齐。
        到这里mScaleType的8种用根据法算是分析完了,现在稍做总结:
FIT_XY:对原图宽高进行放缩,该放缩不保持原比例来填充满ImageView。
MATRIX:不改变原图大小从ImageView的左上角开始绘制,超过ImageView部分不再显示。
CENTER:对原图居中显示,超过ImageView部分不再显示。
CENTER_CROP:对原图居中显示后进行等比放缩处理,使原图最小边等于ImageView的相应边。
CENTER_INSIDE:若原图宽高小于ImageView宽高,这原图不做处理居中显示,否则按比例放缩原图宽(高)是之等于ImageView的宽(高)。
FIT_START:对原图按比例放缩使之等于ImageView的宽高,若原图高大于宽则左对齐否则上对其。
FIT_CENTER:对原图按比例放缩使之等于ImageView的宽高使之居中显示。
FIT_END:对原图按比例放缩使之等于ImageView的宽高,若原图高大于宽则右对齐否则下对其。
        还记得在博文开始的时候说到在ImageView的构造方法中都调用了initImageView()方法么?他的源码如下:

private void initImageView() { mMatrix = new Matrix(); mScaleType = ScaleType.FIT_CENTER; }

可以看到,当我们没有在布局文件中使用scaleType属性或者是没有手动调用setScaleType方法时,那么mScaleType的默认值就是FIT_CENTER。
        好了,有关ImageView的ScaleType的讲解就算结束了,如有错误欢迎指正。以后如有其它属性需要详解,再做记录吧。

原文地址:http://blog.csdn.net/llew2011/article/details/50855655

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-11-10 07:27:41

Android源码系列之深入理解ImageView的ScaleType属性的相关文章

Android源码系列之深入理解ImageView的ScaleType属性_Android

做Android开发的童靴们肯定对系统自带的控件使用的都非常熟悉,比如Button.TextView.ImageView等.如果你问我具体使用,我会给说:拿ImageView来说吧,首先创建一个新的项目,在项目布局文件中应用ImageView控件,代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.

Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

记得在前面的文章中,我带大家一起从源码的角度分析了Android中View的事件分发机制,相信阅读过的 朋友对View的事件分发已经有比较深刻的理解了. 还未阅读过的朋友,请先参考 Android事件分发机 制完全解析,带你从源码的角度彻底理解(上) . 那么今天我们将继续上次未完成的话题,从源码的 角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区 别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View和子

Android AsyncTask完全解析,带你从源码的角度彻底理解

我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴趣的朋友可以参考 Android Handler.Message完全解析,带你从源码的角度彻底理解 . 不过为了更加方便我们在子线程中更新UI元素,Android从1.5版本就引入了一个AsyncTask类,使用它就可以非常灵活方便地从子线程切换到UI线程,我们本篇文章的主角也就正是它了. Asyn

Android源码分析-Alarm机制与Binder的交互

转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/18448997 前言 本次给大家分析的是Android中Alarm的机制以及它和Binder的交互,所用源码为最新的Android4.4.因为Alarm的功能都是通过Binder来完成的,所以,介绍Alarm之前必须要先介绍下它是如何调用Binder来完成定时功能的.由于内容较多,本文会比较长,在文章结构安排上是这样的:首先简单介绍如何使用Alarm并给出其工作原理,接着分析

《Android 源码设计模式解析与实战》——导读

目 录 自序一 自序二 前言 致谢 第1章 走向灵活软件之路--面向对象的六大原则 1.1节优化代码的第一步--单一职责原则1.2节让程序更稳定.更灵活--开闭原则1.3节构建扩展性更好的系统--里氏替换原则1.4节让项目拥有变化的能力--依赖倒置原则1.5节系统有更高的灵活性--接口隔离原则1.6节更好的可扩展性--迪米特原则1.7节总结 第2章 应用最广的模式--单例模式 2.1节单例模式介绍2.2节单例模式的定义2.3节单例模式的使用场景2.4节单例模式UML类图2.5节单例模式的简单示例

在 android studio中如何查看android源码

问题描述 在 android studio中如何查看android源码 比如要看 Activity.class源码 比如要看 Activity.class源码 比如要看 Activity.class源码 比如要看 Activity.class源码 解决方案 声明一个Activity变量,按住ctrl,鼠标点击Activity字样 解决方案二: Android Studio 作为Google的亲儿子,Nexus手机系列所收到的待遇大家有目共睹.Android5.0出来之后,Nexus5第一时间就升

Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置

Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这么多,完结 的也没几个,主要还是自己覆盖的太广了,却又不精通,嘿嘿,工作需要,所以写下了本篇博客 一.VMware 12 我选择的虚拟机试VMware,挺好用的感觉,下载VMware就不说了,善用搜索键嘛,这里我提供一个我现在在用的 下载地址:链接:http://pan.baidu.com/s/1k

ubuntu-Ubuntu14.04怎么安装repo以及下载Android源码(如何翻墙)

问题描述 Ubuntu14.04怎么安装repo以及下载Android源码(如何翻墙) 最近在看老罗的Android源码情景分析一书,想要下载Android源码来研究,可是安装repo时,网络总是连接失败,我在网上找的hosts文件在windows下正常访问google,可是贴到Ubuntu就访问不了,请各位高人指条明路,我该如何下载repo,以及如何利用repo下载Android源码?买VPN的话可靠吗?是否有推荐? 解决方案 参考 android source code from githu

android 编程时,如何在Eclipse中查看Android源码或者第三方组件包源码

相信大多数人都知道怎么在eclipse中看android源码,但是在eclipse中看第三方源码的方法呢,我查看到这篇博文之前我不知道,可能是我才疏学浅,可能很多大牛都知道了,我在这里还是转过来,希望能给不会的人一些帮助. 转自:http://blog.csdn.net/cjjky/article/details/6535426 在学习过程中如果经常阅读源码,理解程度会比较深,学习效率也会比较高,那么如何方便快捷的阅读Android源码? 如何查看Android源码[以Android2.2为例]