- 浏览: 705907 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
utyujin:
作者你好,首先自我注释一下我是一名UI设计师,最近在写关于屏幕 ...
android中的dp,px深度解析 -
eagledame:
<data android:scheme="p ...
Android利用系统广播---监听应用程序安装和卸载[转] -
圣经未来:
虽然帖子距今已有三年,但是我还是来评论一下。对于这段话: 这句 ...
android中的dp,px深度解析 -
passerby_whu:
如果Activity中已经有了很多id了。怎么样保证你指定的i ...
Android Layout 之 RelativeLayout,代码实现相对布局 -
passerby_whu:
u013023750 写道楼主你好 ...
android中的dp,px深度解析
下面是分析ListView初始化的源码流程分析,主要是ListVIew.onLayout过程与普通视图的layout过程完全不同,避免流程交代不清楚,以下是一个流程的思维导图。
思维导图是顺序是从左向右,从上向下。
一、 先看构造函数,上图中1.1就不分析了,主要是读取一些ListView参数,直接来看1.2 ViewGroup构造函数源码
二、接着2 即 ListView.onMeasure方法,只是获取当前ListView的宽高
三、步骤3是重点,ListView的onLayout的流程与普通View的不同
四、步骤4.1 具体分析ListVIew.layoutChildren
五、 分析步骤4.2 ListView.fillFromTop源码
六、查看步骤4.3 ListView.fillDown源码
七、查看步骤4.4 ListView.makeAndAddView源码
八 查看步骤4.5 ListView.setupChild源码
说明:本文为转载,基于android2.3平台。
思维导图是顺序是从左向右,从上向下。
一、 先看构造函数,上图中1.1就不分析了,主要是读取一些ListView参数,直接来看1.2 ViewGroup构造函数源码
private void initViewGroup() { ...... // 初始化保存当前ViewGroup中所有View的数组 mChildren = new View[ARRAY_INITIAL_CAPACITY]; // 初始时其Child个数为0 mChildrenCount = 0; ...... }
二、接着2 即 ListView.onMeasure方法,只是获取当前ListView的宽高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Sets up mListPadding super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 获取当前ListView总宽高 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); ...... setMeasuredDimension(widthSize , heightSize); mWidthMeasureSpec = widthMeasureSpec; }
三、步骤3是重点,ListView的onLayout的流程与普通View的不同
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mInLayout = true; // 初始时changed = true if (changed) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { // ? getChildAt(i).forceLayout(); } mRecycler.markChildrenDirty(); } if (mFastScroller != null && mItemCount != mOldItemCount) { mFastScroller.onItemCountChanged(mOldItemCount, mItemCount); } // ListView实现此方法 layoutChildren(); mInLayout = false; mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR; }
四、步骤4.1 具体分析ListVIew.layoutChildren
@Override protected void layoutChildren() { // 默认为false final boolean blockLayoutRequests = mBlockLayoutRequests; if (!blockLayoutRequests) { // 目的是为了阻止没必要的layout操作,提交效率 mBlockLayoutRequests = true; } else { return; } try { super.layoutChildren(); // 为什么此处要请求重绘? invalidate(); ...... int childCount = getChildCount(); ...... boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } ...... // 把所有child view放置到RecycleBin // 满足条件的话可以重用这些child view final int firstPosition = mFirstPosition; // ListView中Item复用使用此数据结构 final RecycleBin recycleBin = mRecycler; // reset the focus restoration View focusLayoutRestoreDirectChild = null; // Don't put header or footer views into the Recycler. Those are // already cached in mHeaderViews; if (dataChanged) { for (int i = 0; i < childCount; i++) { recycleBin.addScrapView(getChildAt(i), firstPosition+i); } } else { // 创建childCount个数的View放入RecycleBin类activeViews数组中 recycleBin.fillActiveViews(childCount, firstPosition); } ...... // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap(); switch (mLayoutMode) { ...... default: if (childCount == 0) { if (!mStackFromBottom) { final int position = lookForSelectablePosition(0, true); setSelectedPositionInt(position); // 此方法是重点,以下具体分析 sel = fillFromTop(childrenTop); } else { final int position = lookForSelectablePosition(mItemCount - 1, false); setSelectedPositionInt(position); sel = fillUp(mItemCount - 1, childrenBottom); } } else { if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) { sel = fillSpecific(mSelectedPosition, oldSel == null ? childrenTop : oldSel.getTop()); } else if (mFirstPosition < mItemCount) { sel = fillSpecific(mFirstPosition, oldFirst == null ? childrenTop : oldFirst.getTop()); } else { sel = fillSpecific(0, childrenTop); } } break; } // Flush any cached views that did not get reused above recycleBin.scrapActiveViews(); ...... invokeOnItemScrollListener(); } finally { if (!blockLayoutRequests) { mBlockLayoutRequests = false; } }
五、 分析步骤4.2 ListView.fillFromTop源码
// 从上向下在ListView中填充Item View private View fillFromTop(int nextTop) { mFirstPosition = Math.min(mFirstPosition, mSelectedPosition); mFirstPosition = Math.min(mFirstPosition, mItemCount - 1); if (mFirstPosition < 0) { mFirstPosition = 0; } // 具体操作在此 return fillDown(mFirstPosition, nextTop); }
六、查看步骤4.3 ListView.fillDown源码
// 在参数pos下面填充Item View private View fillDown(int pos, int nextTop) { View selectedView = null; // ListView getHeight也是这样计算的 int end = (mBottom - mTop); if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) { end -= mListPadding.bottom; } // 初始化时pos = 0,如果item总数少于一屏幕,执行mItemCount - pos次 // 如果item多余一屏幕,执行end - nextTop次 while (nextTop < end && pos < mItemCount) { // is this the selected item? boolean selected = pos == mSelectedPosition; // 获取Item View对象 View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected); nextTop = child.getBottom() + mDividerHeight; if (selected) { selectedView = child; } pos++; } setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1); return selectedView; }
七、查看步骤4.4 ListView.makeAndAddView源码
// ListView都是通过此方法获取Item View // 具体Item View如何复用,是否需要创建新的Item View都有此方法处理 private View makeAndAddView(int position, int y, boolean flow, int childrenLeft, boolean selected) { View child; // ListView的数据发生变化,肯定Item View之前已经创建好了,无需重新创建 if (!mDataChanged) { // 当前position复用之前创建的视图 child = mRecycler.getActiveView(position); if (child != null) { // 对复用的View针对当前需要进行配置 setupChild(child, position, y, flow, childrenLeft, selected, true); return child; } } // 创建或者重用视图 child = obtainView(position, mIsScrap); // This needs to be positioned and measured setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]); return child; }
八 查看步骤4.5 ListView.setupChild源码
private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft, boolean selected, boolean recycled) { // 判断当前Item View是否选中状态 final boolean isSelected = selected && shouldShowSelector(); final boolean updateChildSelected = isSelected != child.isSelected(); final int mode = mTouchMode; // 是否处于按下状态 final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL && mMotionPosition == position; final boolean updateChildPressed = isPressed != child.isPressed(); // 是否需要重新measure与layout final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested(); // Respect layout params that are already in the view. Otherwise make some up... // noinspection unchecked AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); if (p == null) { p = (AbsListView.LayoutParams) generateDefaultLayoutParams(); } p.viewType = mAdapter.getItemViewType(position); if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter && p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) { attachViewToParent(child, flowDown ? -1 : 0, p); } else { p.forceAdd = false; if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { p.recycledHeaderFooter = true; } // 向ListView(ViewGroup子类)添加当前Item View addViewInLayout(child, flowDown ? -1 : 0, p, true); } // 更新选中状态 if (updateChildSelected) { child.setSelected(isSelected); } // 更新按下状态 if (updateChildPressed) { child.setPressed(isPressed); } if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) { if (child instanceof Checkable) { ((Checkable) child).setChecked(mCheckStates.get(position)); } else if (getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { child.setActivated(mCheckStates.get(position)); } } if (needToMeasure) { int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, mListPadding.left + mListPadding.right, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } // 与普通视图的measure流程不同,ListView是在此处执行具体的当前Item View measure child.measure(childWidthSpec, childHeightSpec); } else { cleanupLayoutState(child); } final int w = child.getMeasuredWidth(); final int h = child.getMeasuredHeight(); final int childTop = flowDown ? y : y - h; if (needToMeasure) { final int childRight = childrenLeft + w; final int childBottom = childTop + h; // 大小改变肯定位置也会发生变化,当前Item View重新进行layout child.layout(childrenLeft, childTop, childRight, childBottom); } else { child.offsetLeftAndRight(childrenLeft - child.getLeft()); child.offsetTopAndBottom(childTop - child.getTop()); } if (mCachingStarted && !child.isDrawingCacheEnabled()) { child.setDrawingCacheEnabled(true); } if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition) != position) { child.jumpDrawablesToCurrentState(); } }
说明:本文为转载,基于android2.3平台。
发表评论
-
深入理解Android的密度独立性
2013-06-17 10:24 1868前言 安卓是一个只 ... -
滑动操作的维度研究
2013-06-13 10:44 1178提示:这篇文章 ... -
移动开发高价值资料参考[持续更新中]
2013-06-13 09:56 1539做人要厚道转载请注明出处:http://zhangkun71 ... -
手机产品设计之用户引导
2013-06-10 20:21 1415在手机产品的设计过程中,由于手机界面 ... -
Android 设计的几处硬伤
2013-06-08 11:31 1575[核心提示] 一些 Andro ... -
Android开发大牛们的博客[持续更新中]
2013-05-31 08:40 27做人要厚道转载请注明出处:http://zhangk ... -
LocalActivityManager的内部机制详解
2013-05-27 15:56 5200LocalActivityManager的内部 ... -
App调试内存泄露之Cursor深入研究
2013-05-24 15:20 0最近在工作中处 ... -
Android设计模式系列(6)--SDK源码之享元模式
2013-05-24 13:12 923享元模式,给我的感 ... -
Android设计模式系列(5)--SDK源码之备忘录模式
2013-05-24 11:15 1083定义(源于GoF《设计模式》):在不破坏封闭的前提下,捕获 ... -
Android设计模式系列(4)--SDK源码之模板方法模式
2013-05-24 10:39 889模板方法,和单例模 ... -
Android设计模式系列(3)--SDK源码之单例模式
2013-05-24 09:43 1007单例模式,可以说是GOF的23种设计模式中最简单的一个。这 ... -
Android设计模式系列(2)--SDK源码之观察者模式
2013-05-23 17:41 1311观察者模式,是一种非常常见的设计模式,在很多系统中随处可见 ... -
Android设计模式系列(1)--SDK源码之组合模式
2013-05-23 17:12 879Android中对组合模式的应用,可谓是泛滥成粥,随处可见, ... -
Android设计模式系列(0)--开篇
2013-05-23 17:11 1203有时候,最难的是坚持;有时候缺少的是信念。 看了很多 ... -
Android Design与Holo Theme详解
2013-05-22 14:06 1545在 国内,有个很有意思的现状。一方面,几个国内最大的公司/企 ... -
GitHub上最火的Android开源项目(完结篇)
2013-05-22 09:22 7700摘要:截至目前,在GitHub“最受欢迎的开源项目”系列文 ... -
二十六个月Android学习工作总结
2013-05-21 16:52 2397本文转自http://www.cnblog ... -
Android中的Layout_weight终极研究
2013-05-17 14:08 3982以前在做UI布局时,也经常用Layout_weight属性 ... -
谷歌I/O大会给开发者带来福音:推出最新Android Studio开发工具
2013-05-17 08:59 1408摘要:在Android Studio发布之后,无论国内外, ...
相关推荐
// 初始化父ListView的Adapter ParentListAdapter parentAdapter = new ParentListAdapter(this, parentData); parentListView.setAdapter(parentAdapter); // 对于每个父ListView的条目,我们需要在getView()中...
在MainActivity.java中,我们需要初始化ListView并设置Adapter。首先,通过`setContentView()`加载主布局,然后找到ListView的引用,如`ListView listView = findViewById(R.id.listView)`。接着,创建前面提到的...
在Android开发中,ListView是一个非常重要的组件,它用于展示大量数据列表,用户可以通过滚动查看所有条目。本教程将深入讲解如何使用ArrayAdapter和SimpleAdapter这两种方式来创建一个简单的ListView实例。 首先,...
// 初始化ViewHolder holder.innerListView = convertView.findViewById(R.id.inner_list_view); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } // 设置内部...
// 初始化ListView ListView listView = (ListView) findViewById(R.id.listView); // 创建适配器 ArrayAdapter<String> adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, items); // 设置...
3. **初始化ListView**:在布局文件中添加ListView控件,并在Activity或Fragment中找到这个控件。 4. **设置适配器**:调用ListView的`setAdapter()`方法,传入创建好的适配器。 5. **监听事件**:如果需要,可以为...
// 构造函数,初始化数据 public ListRadioButtonAdapter(List<String> items) { this.items = items; } @Override public int getCount() { return items.size(); } @Override public Object getItem...
如果是新创建,需要初始化视图;如果是复用,可以直接修改视图内容。 - 使用`holder`模式来提高性能,避免频繁的findViewById操作。 - 根据ListView的`position`参数,判断当前行是否被选中。可以利用`listView....
- **初始化ListView**:在布局文件中添加ListView,设置适配器。 - **定义Adapter**:自定义Adapter,包含数据集和获取数据的方法。 - **监听滚动事件**:为ListView添加OnScrollListener,重写`onScroll()`和`...
在初始化ListView时,可以根据需求设置默认选中的项。 ```java items.get(0).setSelected(true); // 设置第一条为默认选中 adapter = new MyAdapter(this, items); listView.setAdapter(adapter); ``` 三、使用...
初始化convertView ... convertView.setBackgroundResource(R.drawable.list_item_background); // 设置背景 // ... 绑定数据 ... } ``` 另一种方法是利用自定义ViewGroup,例如继承LinearLayout或FrameLayout,...
在Activity中初始化ListView和Adapter,并设置Adapter: ```java ListView listView = findViewById(R.id.list_view); List<String> items = new ArrayList(); // 初始化数据... MyAdapter adapter = new MyAdapter...
- 数据加载:在初始化时加载第一页数据。当用户点击“下一页”按钮时,向服务器请求下一页数据并添加到适配器中,调用notifyDataSetChanged()更新ListView。 - 关注按键事件:在Activity或Fragment中监听“下一页...
2. 初始化ArrayAdapter,传入上下文、布局ID和数据集。 3. 调用ListView的`setAdapter()`方法,传入创建好的Adapter。 五、监听事件 为了响应用户在ListView上的点击操作,我们可以为ListView设置一个....
在Activity或Fragment的onCreate()方法中,初始化ListView、数据列表和Adapter,最后将Adapter设置给ListView。 ```java List<ItemModel> itemList = new ArrayList(); // 添加数据到itemList ItemAdapter adapter...
这段代码展示了如何创建一个`StatisticsForcastListView`对象,并对其进行初始化。其中的关键点在于设置了`setFocusable(false)`来禁用父`ListView`的焦点功能,确保点击事件能够正常触发。 对应的XML布局文件如下...
- 在Activity的布局文件中添加一个ListView,并在代码中初始化它,设置自定义Adapter。 ```xml <ListView android:id="@+id/timeline_list" android:layout_width="match_parent" android:layout_height="match...
3. 在Activity中,初始化ClipboardManager并设置监听器,以便在复制或粘贴时获取和设置数据。 4. 设置ListView的OnItemClickListener,监听单击事件,当用户点击某一行时,获取选中行的数据,创建ClipData并调用...
在MainActivity.cs中,加载布局,初始化ListView,并设置Adapter: ```csharp protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource....
在Activity或Fragment中,我们需要初始化ListView并设置其适配器。适配器通常是自定义的,如`WordAdapter`,继承自`BaseAdapter`。适配器负责将数据绑定到ListView的每一项视图上。我们还需要在适配器中实现`getView...