(转载)Android快速开发偷懒必备,一句话搞定所有ViewGroup的Adapter . 支持自定义ViewGroup
版权声明:本文为博主原创文章,未经博主允许不得转载。
转载请标明出处:
http://blog.csdn.net/zxt0601/article/details/53576092
本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)
代码传送门:喜欢的话,随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter
概述
开发中,经常会用到动态在ScrollView、LinearLayout里addView的事,尤其是ItemView一样时,每次都要写一大堆代码 inflater 动态addView,很烦。
还有就是在嵌套ListView、ScrollView时,想采用LinearLayout替代(这样性能更佳,不明白的看一个控件搞定嵌套ListView),但动态addView步骤神烦。
这个时候就开始期待,能不能有一种快速为任意ViewGroup添加子View的东西。
我之前为此事特意写过一篇LinearLayout封装博文,封装了一个控件使用。试图一个控件搞定嵌套ListView。但是后来发现,采用继承某个ViewGroup做这个事情不够优雅 ,对代码有侵入性,如果有其他ViewGroup需要动态addView,就会写重复的代码 。
前几天有人在群里问,如何方便的给ScrollView动态添加不同种类型的childView,类似RecyclerView那样。我之前的封装由于内部有一个简单的重用机制,只支持单一ItemType,也不支持多种类型的childView。
那么需求就来了:
* 快速简单使用
* 支持任意ViewGroup
* 无耦合
* 无侵入性
* Item支持多种类型
除此之外,我还加入:
* 为ItemView设置OnItemClickListener
* 为ItemView设置OnItemLongClickListener
本文就封装了这么一个东西。
核心:
* 利用Adapter模式封装getView的操作
* 搭配一个工具类,为所有ViewGroup addView。
* 再封装出两个使用快速简单的Adapter 分别用于添加 单一Item布局、多种Item布局。
PS:所以本文也算是填了之前的一个坑,在之前适配器模式博文文末,我就提到要写一篇为流式布局增加Adapter的文章,作为Adapter的实战演练。使用本文封装的Adapter自然可以达到这一点。
由于采用Adapter隔离ViewGroup和ItemView,在切换ViewGroup时,十分方便。
如:在需求让你把一个HorizontalScrollView包裹的水平标签转换成流式布局时,只需要在xml替换控件即可。Adapter将自动完成适配的工作。其他代码一句不用修改。
不BB了,先看看以后如何使用吧,够不够简单粗暴。
使用预览
单一Item类型:
Adapter泛型传入JavaBean,构造函数传入数据集和layout布局,一句代码搞定:
//单一ItemView
ViewGroupUtils.addViews(mLinearLayout, new SingleAdapter<TestBean>(this, mDatas, R.layout.item_test) {
@Override
public void onBindView(ViewGroup parent, View itemView, TestBean data, int pos) {
Glide.with(LinearLayoutActivity.this)
.load(data.getAvatar())
.into((ImageView) itemView.findViewById(R.id.ivAvatar));
((TextView) itemView.findViewById(R.id.tvName)).setText(data.getName());
}
});
效果:
以前会用ScrollView嵌套ListView,现在只要用ScrollView套LinearLayout即可,性能更佳。
多种Item类型:
多种Item类型分两种情况:
数据结构相同:
数据结构相同依然可以给Adapter传入泛型,避免强转:
//多种ItemViewType,但是数据结构相同,可以传入数据结构泛型,避免强转
ViewGroupUtils.addViews(linearLayout, new MulTypeAdapter<MulTypeBean>(this, initDatas()) {
@Override
public void onBindView(ViewGroup parent, View itemView, MulTypeBean data, int pos) {
((TextView) itemView.findViewById(R.id.tvWords)).setText(data.getName() + "");
Glide.with(MulTypeActivity.this)
.load(data.getAvatar())
.into((ImageView) itemView.findViewById(ivAvatar));
}
});
效果:
数据结构不同:
如果数据结构不同,则不用传入泛型,但是使用时需要强转:
//多种Item类型:数据结构不同 不传泛型了 使用时需要强转javaBean,判断ItemLayoutId
ViewGroupUtils.addViews((ViewGroup) findViewById(R.id.activity_mul_type_mul_bean), new MulTypeAdapter(this, datas) {
@Override
public void onBindView(ViewGroup parent, View itemView, IMulTypeHelper data, int pos) {
switch (data.getItemLayoutId()) {
case R.layout.item_mulbean_1:
MulBean1 mulBean1 = (MulBean1) data;
Glide.with(MulTypeMulBeanActivity.this)
.load(mulBean1.getUrl())
.into((ImageView) itemView);
break;
case R.layout.item_mulbean_2:
MulBean2 mulBean2 = (MulBean2) data;
TextView tv = (TextView) itemView;
tv.setText(mulBean2.getName());
}
}
});
数据结构:
public class MulBean1 implements IMulTypeHelper {
private String url;
@Override
public int getItemLayoutId() {
return R.layout.item_mulbean_1;
}
}
public class MulBean2 implements IMulTypeHelper {
private String name;
@Override
public int getItemLayoutId() {
return R.layout.item_mulbean_2;
}
}
Item1布局是一个ImageView,Item2布局是一个TextView
效果:
Item点击事件
item的点击和长按等事件,有两种方法设置,这里以点击事件为例,长按事件同理:
Adapter.onBindView()里设置
在Adapter.onBindView()
方法里能拿到ItemView,自然就可以设置各种事件。类似RecyclerView。
在这里设置优先级更高。原因后文会提到。
@Override
public void onBindView(ViewGroup parent, View itemView, final MulTypeBean data, int pos) {
....
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(mContext, "onBindView里设置:文字是:" + data.getName(), Toast.LENGTH_SHORT).show();
}
});
}
通过ViewGroupUtils设置
可以在ViewGroupUtils.addViews
直接作为参数传入.
也可以用ViewGroupUtils.setOnItemClickListener()
设置 。
优先级比Adapter.onBindView()
里设置低,原因后文会提到。
//设置OnItemClickListener
OnItemClickListener onItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(ViewGroup parent, View itemView, int position) {
Toast.makeText(MulTypeActivity.this, "通过OnItemClickListener设置:" + position, Toast.LENGTH_SHORT).show();
}
};
//可以在`ViewGroupUtils.addViews`直接作为参数传入.\
ViewGroupUtils.addViews(linearLayout, adapter ,onItemClickListener);
//或者 也可以用`ViewGroupUtils.setOnItemClickListener()`设置
ViewGroupUtils.setOnItemClickListener(linearLayout,onItemClickListener);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
看起来还是挺好的,嗯~至少我自己这么觉得,我个人比较喜欢这种0耦合,每一个库都像可组装拆卸的机关枪一样,拿起来就用。而不是笨重功能繁多的重装坦克。
搭配我的得意之作,每次必安利的史上集成最简单侧滑菜单控件。
效果如下:
无特殊设置,仅仅替换ViewGroup为流式布局,替换Item根布局为我撸的侧滑菜单库,能感受到这种0耦合的库的魅力了么。23333333 。
设计思路
下面就让我手摸手带大家实现它。
先看类图。
UML类图:
先简要概括
* 我们的顶层接口IViewGroupAdapter
暴露出两个方法供ViewGroup使用。
ViewGroupUtils
是为任意ViewGroup 动态addView的工具类,只依赖于IViewGroupAdapter
接口即可完成工作。BaseAdapter
是第二层,在这一层引入了数据集,用List<T>
保存。实现IViewGroupAdapter
的方法,重载一个三参数的getView()
方法,供子类去实现。SingleAdapter
是第三层,一个简化的Adapter,只支持单种Item,以LayoutId 构建View。实现getView()
方法,并暴露出onBindView()
供用户快速使用。MulTypeAdapter
也同处第三层,一个支持多种Item的Adapter。依赖IMulTypeHelper
接口,利用其getItemLayoutId()
方法去实现getView()
方法,并暴露出onBindView()
供用户快速使用。
顶层接口设计
顶层接口,即IViewGroupAdapter
。
根据迪米特法则(最少知道原则),我们应该抽象出一个顶层的接口,对ViewGroup暴露出最少的方法供使用。
我们想一下,对于ViewGroup,它最少只需要哪些就能完成我们的需求。
* ChildView是什么—> View
* 有多少ChildView 需要 添加—>count
所以,我们的最顶层接口如下编写:
public interface IViewGroupAdapter {
/**
* ViewGroup调用获取ItemView
*
* @param parent
* @param pos
* @return
*/
View getView(ViewGroup parent, int pos);
/**
* ViewGroup调用,得到ItemCount
*
* @return
*/
int getCount();
}
ok,代码写到这里,后面的我们暂且不提,我们就可以写动态addView的工具类了。因为我们的ViewGroup依赖的所有信息都由IViewGroupAdapter
这个接口提供了。
工具类
ViewGroupUtils
是为任意ViewGroup 动态addView的工具类,不考虑点击事件的情况下,只依赖于 IViewGroupAdapter
接口即可完成工作。
如下编写:
/**
* 为任意ViewGroup 添加ItemViews.
*
* @param viewGroup 必传
* @param adapter 必传,至少提供要add的View和需要add的count
* @param removeViews 是否需要remove掉之前的Views
*/
public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
, boolean removeViews) {
if (viewGroup == null || adapter == null) {
return;
}
//如果需要remove掉之前的Views
if (removeViews && viewGroup.getChildCount() > 0) {
viewGroup.removeAllViews();
}
//开始添加子Views,通过Adapter获得需要添加的Count
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
//通过Adapter获得ItemView
View itemView = adapter.getView(viewGroup, i);
viewGroup.addView(itemView);
}
}
如此即可完成 动态给任意ViewGroup addView 的工作。
不过我们开头提过,我还是想引入ItemView的点击和长按事件的。但是关于这两个ItemListener,还是有一些东西要考虑的。
ItemListener的设计
为ViewGroup提供OnItemClickListener
,有个问题需要考虑:
如果使用者调用了setOnItemClickListener
,且在Adapter
里自己又对ItemView
设置了OnClickListener
,那么究竟该触发哪个Listener
,即它们的优先级。
我们不应该自己靠脑子想答案,还是参照系统原有的设计比较好。既然ListView提供了OnItemClickListener
,那么我们参照它的设计来就行。
先说结论:通过参照ListView的源码,以及实验得知,对ItemView
的OnClickListener
优先级 > ViewGroup的OnItemClickListener
。
为什么?答案在源码中,感兴趣看,不感兴趣直接跳过。
从AbsListView的onTouchEvent()
->onTouchUp()
->PerformClick
->performItemClick
-> AdapterView.performItemClick()
-> AdapterView.mOnItemClickListener
,即可找到答案。
这里不详细分析源码,不是本文重点,简单的说,从入口处是AbsListView的onTouchEvent()
,我们可以知道,ListView本身并没有干预ItemView
的点击事件(即没有为其设置OnClickListener
),是在ItemView
不消耗Touch事件时 才进行Item点击事件的触发。
因此若ItemView
设置了OnClickListener
,AbsListView的onTouchEvent()
将收不到MotionEvent.ACTION_UP
事件,因而也不会触发OnItemClickListener
。所以这决定了ItemView
的OnClickListener
优先级高。
还有一个问题,我们可以通过View.hasOnClickListeners()
这个方法来判断View是否设置了OnClickListener
,但是这个方法在API15才加入,为了能兼容低版本,我采用了另一种方法判断,itemView.isClickable()
,如果true,我当做有点击事件,如果false,我当做没有。
其实在ListView中这个问题也是一样的,itemView.isClickable()
为true的话,点击事件就被拦截住,不会分发至AbsListView的onTouchEvent()
里了。所以我们这么写是没问题,并且是正确的。
ItemListener的完整实现:
既然如此,那么我们在程序中,应该如下编写:
for (int i = 0; i < count; i++) {
View itemView = adapter.getView(viewGroup, i);
viewGroup.addView(itemView);
//添加点击事件
if (null != onItemClickListener && !itemView.isClickable()) {
final int finalI = i;
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(viewGroup, view, finalI);
}
});
}
//添加点击事件
if (null != onItemLongClickListener && !itemView.isLongClickable()) {
final int finalI = i;
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return onItemLongClickListener.onItemLongClick(viewGroup, view, finalI);
}
});
}
}
所以完整的addViews()
如下:
/**
* 为任意ViewGroup 添加ItemViews.
*
* @param viewGroup 必传
* @param adapter 必传,至少提供要add的View和需要add的count
* @param removeViews 是否需要remove掉之前的Views
* @param onItemClickListener Item点击事件
* @param onItemLongClickListener Item长按事件
*/
public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
, boolean removeViews
, final OnItemClickListener onItemClickListener
, final OnItemLongClickListener onItemLongClickListener) {
if (viewGroup == null || adapter == null) {
return;
}
//如果需要remove掉之前的Views
if (removeViews && viewGroup.getChildCount() > 0) {
viewGroup.removeAllViews();
}
//开始添加子Views,通过Adapter获得需要添加的Count
int count = adapter.getCount();
for (int i = 0; i < count; i++) {
//通过Adapter获得ItemView
View itemView = adapter.getView(viewGroup, i);
viewGroup.addView(itemView);
//添加点击事件,itemView之前没有点击事件才会去设置
if (null != onItemClickListener && !itemView.isClickable()) {
final int finalI = i;
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(viewGroup, view, finalI);
}
});
}
//添加长按事件itemView之前没有长按事件才会去设置
if (null != onItemLongClickListener && !itemView.isLongClickable()) {
final int finalI = i;
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return onItemLongClickListener.onItemLongClick(viewGroup, view, finalI);
}
});
}
}
}
实际中,我们可能不需要设置Listener,为了快速使用,我又提供了两个重载方法:
/**
* 为任意ViewGroup 添加ItemViews.
* 并且会清除掉之前所有add过的View
*
* @param viewGroup 必传
* @param adapter 必传,至少提供要add的View和需要add的count
*/
public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter) {
addViews(viewGroup, adapter, true, null, null);
}
/**
* 为任意ViewGroup 添加ItemViews.
* 并且会清除掉之前所有add过的View
*
* @param viewGroup 必传
* @param adapter 必传,至少提供要add的View和需要add的count
* @param onItemClickListener Item点击事件
*/
public static void addViews(final ViewGroup viewGroup, IViewGroupAdapter adapter
, final OnItemClickListener onItemClickListener) {
addViews(viewGroup, adapter, true, onItemClickListener, null);
}
若不在addViews()
里设置ItemListener,也可以通过setOnItemClickListener()
和setOnItemLongClickListener()
设置,不过这两个方法必须在addViews()方法之后调用:
/**
* 为任意ViewGroup设置OnItemClickListener.
* 该方法必须在addViews()方法之后调用,否则无效。
* 因为ItemView 必须被添加在ViewGroup里才能遍历到。
* 建议直接在addViews()方法里传入OnItemClickListener进行设置,性能更高
*
* @param viewGroup
* @param onItemClickListener
*/
public static void setOnItemClickListener(final ViewGroup viewGroup, final OnItemClickListener onItemClickListener) {
if (viewGroup == null || onItemClickListener == null) {
return;
}
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
final View itemView = viewGroup.getChildAt(i);
//itemView之前没有点击事件才会去设置
if (null != itemView && !itemView.isClickable()) {
final int finalI = i;
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onItemClick(viewGroup, itemView, finalI);
}
});
}
}
}
/**
* 为任意ViewGroup设置OnItemLongClickListener.
* 该方法必须在addViews()方法之后调用,否则无效。
* 因为ItemView 必须被添加在ViewGroup里才能遍历到。
* 建议直接在addViews()方法里传入OnItemLongClickListener进行设置,性能更高
*
* @param viewGroup
* @param onItemLongClickListener
*/
public static void setOnItemLongClickListener(final ViewGroup viewGroup, final OnItemLongClickListener onItemLongClickListener) {
if (viewGroup == null || onItemLongClickListener == null) {
return;
}
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
final View itemView = viewGroup.getChildAt(i);
//itemView之前没有长按事件才会去设置
if (null != itemView && !itemView.isLongClickable()) {
final int finalI = i;
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return onItemLongClickListener.onItemLongClick(viewGroup, itemView, finalI);
}
});
}
}
}
Adapter
终于到了我们的重头戏,Adapter。
BaseAdapter
BaseAdapter
是第二层,在这一层引入了数据集,用List<T>
保存。实现IViewGroupAdapter
的方法,重载一个三参数的getView()
方法,供子类去实现。
它和我们平时写的ListView、RecyclerView的Adapter就比较像了,我也是参照平时的写法。
核心就是实现IViewGroupAdapter
的getView(ViewGroup parent, int pos)
方法,增加一个数据,工作转交给三参数的getView(ViewGroup parent, int pos, T data)
方法。
子类应该 实现 getView(ViewGroup parent, int pos, T data)
方法,在其中inflate or new 出 ItemView,并绑定数据。
public abstract class BaseAdapter<T> implements IViewGroupAdapter {
protected List<T> mDatas;
protected Context mContext;
protected LayoutInflater mInflater;
/**
* ViewGroup调用获取ItemView,create bind一起做
*
* @param parent
* @param pos
* @return
*/
@Override
public View getView(ViewGroup parent, int pos) {
return getView(parent, pos, mDatas.get(pos));
}
/**
* 实际的createItemView的地方
*
* @param parent
* @param pos
* @param data
* @return
*/
public abstract View getView(ViewGroup parent, int pos, T data);
/**
* ViewGroup调用,得到ItemCount
*
* @return
*/
@Override
public int getCount() {
return mDatas != null ? mDatas.size() : 0;
}
}
SingleAdapter
SingleAdapter
是第三层,一个简化的Adapter,只支持单种Item,以LayoutId 构建View。实现getView()
方法,并暴露出onBindView()
供用户快速使用。
使用时,一般将数据结构的泛型传入,配合构造函数传入的ItemLayoutId使用。
它继承自BaseAdapter
,所以它了实现getView(ViewGroup parent, int pos, T data)
方法。在根据传入的itemLayoutId inflate出ItemView后,会回调onBindView(ViewGroup parent, View itemView, T data, int pos)
方法,并返回ItemView供ViewGroup使用。
在onBindView(ViewGroup parent, View itemView, T data, int pos)
方法里,我们完成数据绑定的工作。例如加载图片,也可以设置点击事件。
public abstract class SingleAdapter<T> extends BaseAdapter<T> {
private int mItemLayoutId;
@Override
public View getView(ViewGroup parent, int pos, T data) {
//实现getView
View itemView = /*onCreateView(parent, pos)*/mInflater.inflate(mItemLayoutId, parent, false);
onBindView(parent, itemView, data, pos);
return itemView;
}
/**
* 暴漏这个 让外部bind数据
*
* @param parent
* @param itemView
* @param data
* @param pos
*/
public abstract void onBindView(ViewGroup parent, View itemView, T data, int pos);
}
MulTypeAdapter
MulTypeAdapter
也同处第三层,一个支持多种Item的Adapter。依赖IMulTypeHelper
接口,利用其getItemLayoutId()
方法去实现getView()
方法,并暴露出onBindView()
供用户快速使用。
public abstract class MulTypeAdapter<T extends IMulTypeHelper> extends BaseAdapter<T> {
@Override
public View getView(ViewGroup parent, int pos, T data) {
View itemView = mInflater.inflate(data.getItemLayoutId(), parent, false);
onBindView(parent, itemView, data, pos);
return itemView;
}
/**
* 暴漏这个 让外部bind数据
*
* @param parent
* @param itemView
* @param data
* @param pos
*/
public abstract void onBindView(ViewGroup parent, View itemView, T data, int pos);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
IMulTypeHelper
接口,同样简单:
public interface IMulTypeHelper {
int getItemLayoutId();
}
- 1
- 2
- 3
- 1
- 2
- 3
总结
代码传送门:喜欢的话,随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter
因为想支持任意ViewGroup,对ViewGroup代码无侵入性,因而对部分功能进行了取舍,例如设置OnItemXXXListener
,如果采用继承ViewGroup,嵌入代码,可以做到不强制addViews()
和setOnItemClickListener()
顺序。
通过上文我们能感受到一些面向接口编程的奥义,例如我们只需要设计好顶层的接口IViewGroupAdapter
,在没写剩下的xxxAdapter时,工具类都可以写好,编译通过。
这在以后扩展时,例如,我数据集不能用List来保存了,我可能是多个List or Map 等等,只需要实现IViewGroupAdapter
接口即可定制一个Adapter。其他代码不需任何修改。
有人说过,设计模式怎么学,就是先学完一遍所有的设计模式。然后再全部忘掉他们,只要记住SOLID原则即可。
我觉得很有道理,就像我之前一直在纠结代理模式和装饰者模式的区别,后来我想,编码时,我管它是什么模式,只要写出来的是易维护的代码即可。
to do list
- 考虑加入复用缓存池
- 考虑替换
onBindView()
的ItemView
->通用的ViewHolder
,这样可以少写一些findViewById()
代码。 - 整合DataBinding 的通用Adapter入库。
- 整合 RecyclerView、ListView的通用Adapter入库。
- 加入一些自定义ViewGroup入库,例如流式布局,九宫格,Banner轮播图。
下文预告:
一个用ScrollView很容易实现,但RecyclerView、ListView就无法实现的动画效果,仿淘宝会员中心等级动画。凸显为所有ViewGroup增加Adapter模式的重要性。
DataBinding篇隆重登场
感兴趣可以去阅读
http://blog.csdn.net/zxt0601/article/details/53618694
转载请标明出处:
http://blog.csdn.net/zxt0601/article/details/53576092
本文出自:【张旭童的博客】(http://blog.csdn.net/zxt0601)
代码传送门:喜欢的话,随手点个star。多谢
https://github.com/mcxtzhang/all-base-adapter
- 顶
- 14
- 踩
- 1
- 上一篇【Android】你可能不知道的Support(一) 0步自动定向刷新:SortedList
- 下一篇【Android】快速开发偷懒必备(二) 支持DataBinding啦~爽炸,一行实现花式列表
- • 教你搞定Android自定义ViewGroup
- • 【直播】机器学习&数据挖掘7周实训--韦玮
- • 一行代码搞定标签换行,自定义ViewGroup
- • 【直播】大中型UGC信息网站SEO分享--乔向阳
- • 【Android】快速开发偷懒必备(二) 支持DataBinding啦~爽炸,一行实现花式列表
- • 【直播】打通Linux脉络 进程、线程和调度--宋宝华
- • 自定义ViewGroup+Adapter
- • 【套餐】Java高级程序员专业学习路线--肖海鹏
- • Android 手把手教您自定义ViewGroup源码分析加注释
- • 【课程】C++语言基础--贺利坚
- • Android自定义ViewGroup
- • 【课程】深度学习基础与TensorFlow实践--AI100
- • 【Cocos2d-x】新手自学(十)分辨率自适应!一句话搞定IOS android windows!!
- • android自定义viewGroup仿Scrollview详解
- • ListView自定义Adapter中getView(int position, View convertView, ViewGroup parent) 使用
- • Android自定义ViewGroup(一)
- 8楼 Xiaohui783 2017-05-04 11:59发表 [回复]
- 大神,看了你Git上的代码,添加了ViewHolder ,但是发现还是创建很多ViewHolder,这里的ViewHolder只是单纯的减少findViewById 的代码吗?
- 7楼 Xiaohui783 2017-05-04 11:56发表 [回复]
- 大神,刚去看了你Git 上的代码,看到你写了复用ViewHolder,但是日志发现还是会创建datas长度个数的的ViewHolder ,这里单单只是为了少用findViewById吗
- 6楼 Only_Engineer 2016-12-28 15:43发表 [回复]
- 好文很多啊
(转载)Android快速开发偷懒必备,一句话搞定所有ViewGroup的Adapter . 支持自定义ViewGroup的更多相关文章
- 【Android】快速开发偷懒必备(二) 支持DataBinding啦~爽炸,一行实现花式列表[申明:来源于网络]
[Android]快速开发偷懒必备(二) 支持DataBinding啦~爽炸,一行实现花式列表[申明:来源于网络] 地址:http://blog.csdn.net/zxt0601/article/de ...
- (转载)实例详解Android快速开发工具类总结
实例详解Android快速开发工具类总结 作者:LiJinlun 字体:[增加 减小] 类型:转载 时间:2016-01-24我要评论 这篇文章主要介绍了实例详解Android快速开发工具类总结的相关 ...
- Android 快速开发系列 打造万能的ListView GridView 适配器
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38902805 ,本文出自[张鸿洋的博客] 1.概述 相信做Android开发的写 ...
- OpenCV3.4.1快速集成到Android studio中,10分钟搞定
OpenCV3.4.1快速集成到Android studio中,10分钟搞定 转载 https://blog.csdn.net/yu540135101/article/details/8259 ...
- Android快速开发不可或缺的11个工具类
Android快速开发不可或缺的11个工具类 :http://www.devst ore.cn/code/info/363.html
- Android快速开发不可或缺的11个工具类(下载)
功能分类:工具 支持平台:Android 运行环境:Eclipse 开发语言:Java 开发工具:Eclipse 源码大小:11.45KB 下载地址:ht ...
- 【高德地图API】一句话搞定webmap(一)——轻地图组件
原文:[高德地图API]一句话搞定webmap(一)——轻地图组件 摘要: 遥想当年,在APP中加入LBS元素相当困难:要刻苦学习java,要刻苦学习iOS开发,要刻苦学习javascript…… 而 ...
- 一句话搞定webmap(一)——轻地图组件
摘要: 遥想当年.在APP中增加LBS元素相当困难:要刻苦学习java,要刻苦学习iOS开发,要刻苦学习javascript-- 而现在.要制作一张地图真是越来越easy了!居然仅仅须要一句话.就能够 ...
- AFNetworking3.0+MBProgressHUD二次封装,一句话搞定网络提示
对AFNetworking3.0+MBProgressHUD的二次封装,使用更方便,适用性非常强: 一句话搞定网络提示: 再也不用担心网络库更新后,工程要修改很多地方了!网络库更新了只需要更新这个封装 ...
随机推荐
- Ubuntu14.04引导菜单修复
原文链接:http://www.metsky.com/archives/636.html 独立分区下的Ubuntu引导菜单修复有点麻烦,执行挂载等命令时要小心检查,修复此类引导,首先需要确保当前系统和 ...
- 00--Qt Creator 你必须要掌握的快捷操作
Qt Creator 你必须要掌握的快捷操作 多使用快捷键能显著提高工作效率,尽可能减少键盘,鼠标之间切换所浪费的时间.我这里列出个人认为非常重要必须掌握的 Qt Creator 快捷键.看你知道几个 ...
- Zbrush 4R7中的镜像功能是怎么使用的?
ZBrush一款3D图形绘制软件,功能十分强大,在雕刻建模的时候镜像工具是我们经常要用到的,它可以方便快捷雕刻对称的模型,那么ZBrush®中怎样镜像呢,本文小编将做详细介绍. ZBrush 3D镜像 ...
- MongoDB经典入门(1)--安装
一.前言 最近开始学习非关系型数据库MongoDB,却在博客园上找不到比较系统的教程,很多资料都要去查阅英文网站,效率比较低下.本人不才,借着自 学的机会把心得体会都记录下来,方便感兴趣的童鞋分享讨论 ...
- MySQL数据表查询操
准语法结构:编写DQL时一定要严格按照此语法的顺序来实现!/* SELECT [ALL | DISTINCT] ALL表示查询出所有的内容 DISTINCT 去重 {* | 表名.* | 表名.字段名 ...
- Python基础学习_01字符串的拼接(字符串的格式化输出)
# 字符串的拼接 ---字符串的格式化输出 # 字符串的拼接 ---字符串的格式化输出 name = input("name:") age = input("age:&q ...
- 基于BootStrap,FortAweSome,Ajax的学生管理系统
一. 基于BootStrap,FortAweSome,Ajax的学生管理系统代码部分 1.students.html <1>html页面文件 <!DOCTYPE html> & ...
- 记录python爬取猫眼票房排行榜(带stonefont字体网页),保存到text文件,csv文件和MongoDB数据库中
猫眼票房排行榜页面显示如下: 注意右边的票房数据显示,爬下来的数据是这样显示的: 网页源代码中是这样显示的: 这是因为网页中使用了某种字体的缘故,分析源代码可知: 亲测可行: 代码中获取的是国内票房榜 ...
- alg--动态规划(dynamic planning)
怎么开头呢? 一句话概括吧, dp的思想就是递归的反思想. 参考的理化: https://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.h ...
- join()与os.path.join()的用法
join:连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符)连接生成一个新的字符串 os.path.join(): 将多个路径组合后返回 一.函数说明 1.join()函数 语法:‘ ...