解决ListView列表setEmptyView⽆效问题及源码解析
很多童鞋们认为ListView的setEmptyView设置空界⾯⽆效的。通常在⽹上查了查,然后来按照⽹谁上的做法直接复制粘贴⼀下。效果出来就OK了。⾝为⼀个开发者,我们既要知其然,也要知道其所以然。
⽬前我们⼤部分是这样做的:
View view;
inflater = LayoutInflater.from(this);
view =inflater.inflate(pty_nodata,null);
((ViewGroup)llr_Parent()).addView(emptyView);
lr_recycleView_query.setEmptyView(emptyView);
setEmptyView()其实是AdapterView的⽅法,⽽我们开发中常⽤到的ListView, GridView, ExpandableListView等都是继承于AdapterView的,所以可以直接调⽤这个⽅法。
so问题来了。
为什么⼀定要加上
((ViewGroup)llr_Parent()).addView(emptyView);
这⾏代码呢?
请看源码:
/**
* Sets the view to show if the adapter is empty
*/
@android.view.RemotableViewMethod
public void setEmptyView(View emptyView) {
mEmptyView = emptyView;
// If not explicitly specified this view is important for accessibility.
if (emptyView != null
&& ImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
}
final T adapter = getAdapter();
final boolean empty = ((adapter == null) || adapter.isEmpty());
updateEmptyStatus(empty);
}
从上⾯可以看出当emptyView部位空时,先通过updateEmptyStatus(empty);进⾏更新当前的View。
在setEmptyView⽅法中将传过来的emptyView赋值给全局的mEmptyView。在其他地⽅也可以对其进⾏处理。
接下来是看⼀下updateEmptyStatus(empty)的源码:
/**
* Update the status of the list based on the empty parameter.  If empty is true and
* we have an empty view, display it.  In all the other cases, make sure that the listview
* is VISIBLE and that the empty view is GONE (if it's not null).
*/
private void updateEmptyStatus(boolean empty) {
if (isInFilterMode()) {
empty = false;
}
if (empty) {
if (mEmptyView != null) {
mEmptyView.setVisibility(View.VISIBLE);
setVisibility(View.GONE);
} else {
// If the caller just removed our empty view, make sure the list view is visible
setVisibility(View.VISIBLE);
}
// We are now GONE, so pending layouts will not be dispatched.
// Force one here to make sure that the state of the list matches
// the state of the adapter.
if (mDataChanged) {
}
} else {
if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
setVisibility(View.VISIBLE);
}
}
updateEmptyStatus源码很简单,根据empty这个状态值进⾏设定mEmptyView 是否是显⽰。
如果adapter部位空,则执⾏:
if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
setVisibility(View.VISIBLE);
为空时的时候:
if (mEmptyView != null) {
mEmptyView.setVisibility(View.VISIBLE);
set Visibility(View.GONE);
} else {
// If the caller just removed our empty view, make sure the list view is visible
set Visibility(View.VISIBLE);
}
源码中仅仅只是对mEmptyView进⾏了隐藏和显⽰。并未对其进⾏说明。这就表明了,
mEmptyView和当前的list或者是GridView及其其他View是同⼀级的关系。同时也说明了为什么需要⽤到((ViewGroup)llr_Parent()).addView(emptyView); 才能起到效果。
这也可能是Android源码时的⼀个不⾜之处。针对于Android上的有些⽼早的⽼司机早就想好了对策。⽐如说PullToRefreshAdapterViewBase就重写了setemptyView⽅法。
public final void setEmptyView(View newEmptyView) {
FrameLayout refreshableViewWrapper = getRefreshableViewWrapper();
if (null != newEmptyView) {
// New view needs to be clickable so that Android recognizes it as a
// target for Touch Events
newEmptyView.setClickable(true);
ViewParent newEmptyViewParent = Parent();
if (null != newEmptyViewParent && newEmptyViewParent instanceof ViewGroup) {
((ViewGroup) newEmptyViewParent).removeView(newEmptyView);
}
// We need to convert any LayoutParams so that it works in our
/
/ FrameLayout
FrameLayout.LayoutParams lp = LayoutParams());
if (null != lp) {
refreshableViewWrapper.addView(newEmptyView, lp);
} else {
refreshableViewWrapper.addView(newEmptyView);
}
}
if (mRefreshableView instanceof EmptyViewMethodAccessor) {
((EmptyViewMethodAccessor) mRefreshableView).setEmptyViewInternal(newEmptyView);
} else {
mRefreshableView.setEmptyView(newEmptyView);
}
mEmptyView = newEmptyView;
}
这既是为什么有些时候不做处理也可以有效果。
对EmptyView的封装
**
* 功能:列表空界⾯显⽰
* ⽤于listView ,GridView ,RecycleView 的setEmpety⽅法
* @author yuyahao
* 备注:其他童鞋们可对其进⾏拓展 eg: 添加监听,切换布局
*/
public class EmptyView extends LinearLayout {
private TextView  tv_no_message;
private ImageView iv_empety_mageger;
private LinearLayout ll_no_manager;
private LinearLayout ll_no_message_root;
public EmptyView(Context context) {
super(context);
init();
// TODO Auto-generated constructor stub
}
public EmptyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// TODO Auto-generated method stub
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(pty_view, null);
iv_empety_mageger = (ImageView) view.findViewById(R.id.iv_empety_mageger);
tv_no_message = (TextView) view.findViewById(R.id.tv_no_message);
ll_no_manager = (LinearLayout) view.findViewById(R.id.ll_no_manager);
ll_no_message_root = (LinearLayout) view.findViewById(R.id.ll_no_message_root);
ll_no_message_root = (LinearLayout) view.findViewById(R.id.ll_no_message_root);
addView(view);
}
/**
* ⼀定要调⽤该⽅法
* @param
*/
public View mustCallInitWay(View view){
if(view != null){
ViewGroup.LayoutParams  params = ll_no_LayoutParams();
params.width = Context());
params.height = Context()) - DensityUtil.Context(),50);            ((Parent()).addView(this,params);
}
return this;
}
public void setNoMessageText(CharSequence text) {
tv_no_message.setText(text);
tv_no_message.setVisibility(View.VISIBLE);
}
/********修改⽂字的颜⾊**********/
public void setMessageTextColor2(int colorResId) {
tv_no_message.setTextColor(colorResId);
tv_no_message.setVisibility(View.VISIBLE);
}
/**
gridview不显示* 显⽰不同的⽂字提⽰及其图⽚提⽰
*/
public View setMyManager(String showNoTip,int showNoIamgeViewResId,int textSize,int colorResId){
iv_empety_mageger.setImageResource(showNoIamgeViewResId);
tv_no_message.setTextColor(colorResId);
tv_no_message.setText(showNoTip);
tv_no_message.setTextSize(textSize);
tv_no_message.setVisibility(View.VISIBLE);
return this;
}
/**
* 显⽰不同的⽂字提⽰及其图⽚提⽰
*/
public View setMyManager(String showNoTip,int showNoIamgeViewResId){
iv_empety_mageger.setImageResource(showNoIamgeViewResId);
tv_no_message.setText(showNoTip);
tv_no_message.setVisibility(View.VISIBLE);
return this;
}
/**
* 显⽰不同的⽂字提⽰及其图⽚提⽰
*/
public View setMyManager(int showNoIamgeViewResId){
iv_empety_mageger.setImageResource(showNoIamgeViewResId);
iv_empety_mageger.setVisibility(View.VISIBLE);
return this;
}
/**
* 显⽰不同的⽂字提⽰
*/
public View setMyManager(String showNoTip){
tv_no_message.setText(showNoTip);
tv_no_message.setVisibility(View.VISIBLE);
return this;
}
/**
/**
* 是否显⽰⽂字
*/
public View isShowTextTipMassager(boolean isShow){
if(isShow){
tv_no_message.setVisibility(View.VISIBLE);
}
return this;
}
/**
* 是否显⽰⽂字
*/
public View isShowTextTipMassager(boolean isShow,String showNoTip){
if(isShow){
tv_no_message.setVisibility(View.VISIBLE);
tv_no_message.setText(showNoTip);
}else{
tv_no_message.setVisibility(View.GONE);
tv_no_message.setText(showNoTip);
}
return this;
}
/**
* 是否显⽰图⽚
*/
public View isShowIamgeMassager(boolean isShow,int showNoIamgeViewResId){
if(isShow){
iv_empety_mageger.setVisibility(View.VISIBLE);
iv_empety_mageger.setImageResource(showNoIamgeViewResId);
}else{
iv_empety_mageger.setVisibility(View.GONE);
}
return this;
}
/**
* 是否显⽰图⽚
*/
public View isShowIamgeMassager(boolean isShow){
if(isShow){
iv_empety_mageger.setVisibility(View.VISIBLE);
}else{
iv_empety_mageger.setVisibility(View.GONE);
}
return this;
}
}
如何调⽤:
EmptyView emptyView = new EmptyView(this);
emptyView.mustCallInitWay(lr_recycleView_query);
lr_recycleView_query.setEmptyView(emptyView);
注意:如果你的⼦布局中有剁成⽗布局进⾏嵌套,这个时候
((Parent()).addView(this);
这个⽅法是⽆效的。addView的时候布局中的⼤⼩match_parent是没有效果的,它总是以包裹内容进⾏填充的。显⽰效果:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。