*:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
/* BLOCKS
=============================================================================*/
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
/* HEADERS
=============================================================================*/
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: #000;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777;
font-size: 14px;
}
body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}
/* LINKS
=============================================================================*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* LISTS
=============================================================================*/
ul, ol {
padding-left: 30px;
}
ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}
ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt>:first-child {
margin-top: 0px;
}
dl dt>:last-child {
margin-bottom: 0px;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd>:first-child {
margin-top: 0px;
}
dl dd>:last-child {
margin-bottom: 0px;
}
/* CODE
=============================================================================*/
pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}
/* QUOTES
=============================================================================*/
blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
blockquote>:first-child {
margin-top: 0px;
}
blockquote>:last-child {
margin-bottom: 0px;
}
/* HORIZONTAL RULES
=============================================================================*/
hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}
/* TABLES
=============================================================================*/
table th {
font-weight: bold;
}
table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}
table tr {
border-top: 1px solid #ccc;
background-color: #fff;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
/* IMAGES
=============================================================================*/
img {
max-width: 100%
}
-->
模板代码 - 列表和下拉刷新
手机应用一个常见的界面模式就是:顶部的ActionBar + TabStrip导航,中间的ListView,可以下拉刷新或者是底部的加载更多。通常ListView都需要是显示多种类型的条目。
ActionBar-ViewPager-Fragment
- 自定义一个带有ActionBar的主题:这样既可以获得ActionBar效果,又可以自己调整ActionBar的显示,如背景和字体等。下面主要是重新指定了tab_indicator。
//在values/style.xml里:actionbar_tab_indicator的内容省略,官方文档有,很罗嗦。 <style name="CustomActionBarTheme" parent="@android:style/Theme.Holo.Light"> <item name="android:actionBarTabStyle">@style/MyActionBarTabs</item> </style> <!-- ActionBar tabs styles --> <style name="MyActionBarTabs" parent="@style/android:Widget.Holo.ActionBar.TabView"> <!-- tab indicator --> <item name="android:background">@drawable/actionbar_tab_indicator</item> </style>
- 让Activity继承FragmentActivity,定义一个继承自FragmentStatePagerAdapter的子类——MyPagerAdapter,活动布局中放置一个ViewPager填充整个界面。Activity.onCreate方法里为ActionBar设置属性:
ActionBar actionBar = getActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setHomeButtonEnabled(true); //FragmentStatePagerAdapter的public Fragment getItem(int position)等相关方法正是配合ViewPager来完成 //整个界面里切换Fragment的功能。它一直保持正在显示的,和左右(如果有)2个Fragment实例。 //关联viewPager和FragmentStatePagerAdapter实例 viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
- 在布局文件,ViewPager内放置android.support.v4.view.PagerTabStrip控件,这样可以显示ActionBar的tabs为特殊的样式,就是一直显示“左、中、右” 3个tab指示器,左右滑动ViewPager切换Fragment时,或者点击tab标签时左右滚动来显示更多其它的tab。(以后上图。。。)
ListView显示多种类型的条目
ListView支持显示多种类型的条目,并且可以同时复用不同条目的view。假设我们使用ListView显示一个下载应用的列表界面,在ListView的底部显示“加载更多”这样的按钮,那么就是让ListView同时显示2种类型的条目。
ListView的getView方法正是我们为ListView提供要显示条目的地方,为了便于为普通的条目对应的view对象添加更多的控制,可以定义ViewHolder来组合View,并负责它的创建和状态控制。
- 为显示的“应用信息”列表条目定义AppInfoViewHolder,它包含一个name和icon,布局文件item_appinfo是简单的ImageView和TextView,其ViewHolder定义如下:
class AppInfoViewHolder{ ImageView icon; TextView name; View itemView; public AppInfoViewHolder(){ itemView = View.inflate(AppHelper.getContext(), R.layout.item_appinfo,null); icon = (ImageView)itemView.findViewById(R.id.appIcon); name = (TextView)itemView.findViewById(R.id.appName); //关联当前Holder和View itemView.setTag(this); } public void setViewData(AppInfo info){ icon.setImageResource(info.getIconResId()); name.setText(info.getName()); } public View getView(){ return itemView; } }
- 之后定义“加载更多”的LoadMoreViewHolder:
public class LoadMoreViewHolder { private View contentView; private View loadMore; private View loading; private Button bt_loadMore; OnLoadMoreExecute loadMoreListener; public LoadMoreViewHolder{ contentView = View.inflate(UIUtils.getContext(), R.layout.load_more, null); loadMore = contentView.findViewById(R.id.view_load_more); loading = contentView.findViewById(R.id.view_loading); bt_loadMore = (Button) contentView.findViewById(R.id.bt_load_more); //关联当前Holder和View contentView.setTag(this); showLoadMore(); } public interface OnLoadMoreExecute{ void loadMore(LoadMoreHolder holder); } //设置“加载更多”的业务逻辑 public void setOnLoadMoreListener(OnLoadMoreExecute action){ loadMoreListener = action; if(loadMoreListener != null ){ bt_loadMore.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { loadMoreListener.loadMore(LoadMoreViewHolder.this); } }); } } public void showLoading(){ loading.setVisibility(View.VISIBLE); loadMore.setVisibility(View.INVISIBLE); } public void showLoadMore(){ loadMore.setVisibility(View.VISIBLE); loading.setVisibility(View.INVISIBLE); } public View getView(){ return contentView; } }
LoadMoreViewHolder提供加载更多和加载中两种界面,当数据加载失败或者没有更多数据时,可以使用Toast进行界面提示,当然也可以动态改变“加载更多”按钮的显示文本。
上面的LoadMoreViewHolder显示了使用ViewHolder来管理每个列表条目对应的View是非常方便的,这样可以让ListView的每个条目的创建、状态修改的代码都集中在一个类中,如果不是使用ViewHolder来组合View,那么对View状态的修改的代码就很容易分散地复杂起来。
- ListView的多条目类型复用,主要是getView、getViewTypeCount、getItemViewType和getCount搭配使用。
public class AppInfoAdapter extends BaseAdapter { List<AppInfo> infos; private final int ITEMTYPE_APP = 0;//
条目类型对应的值范围是:0 ~
private final int ITEMTYPE_MORE = 1; //显示的条目总数 @Override public int getCount() { return infos.size() + 1; } //position处的条目的类型,条目类型对应的值范围是:0 ~getViewTypeCount()
-1getViewTypeCount()
-1 @Override public int getItemViewType(int position) { if(position == infos.size()){ return ITEMTYPE_MORE; }else{ return ITEMTYPE_APP; } } //显示条目的类型数 @Override public int getViewTypeCount() { return 2; } //根据position和convertView来创建或复用条目 @Override public View getView(int position, View convertView, ViewGroup parent) { int viewType = getItemViewType(position); View view = null; switch (viewType) { case ITEMTYPE_APP: AppInfoViewHolder appHolder = null; if(convertView == null){ appHolder = new AppInfoViewHolder(); }else{ appHolder = (AppInfoViewHolder) view.getTag(); } appHolder.setViewData(infos.get(position)); view = appHolder.getView(); break; case ITEMTYPE_MORE: if(convertView == null){ LoadMoreViewHolder moreHolder = new LoadMoreViewHolder(); moreHolder.setOnLoadMoreListener(new OnLoadMoreExecute(){ @Override public void loadMore(LoadMoreViewHolder holder){ asyncLoadMoreData(holder); } }); view = moreHolder.getView(); }else{ view = convertView; } break; } return view; } private void asyncLoadMoreData(LoadMoreViewHolder holder){ holder.showLoading(); new Thread(){ @Override public void run() { final List<AppInfo> newData = new AppInfoDao.getPageData(2); UIHelper.runOnUiThread(new Runnable(){ @Override public void run() { if(newData == null){ Toast.makeText(AppHelper.getContext(), "获取失败,稍后重试。", Toast.LENGTH_SHORT).show(); }else if(newData.size() == 0){ Toast.makeText(AppHelper.getContext(), "没数据了,稍后重试。", Toast.LENGTH_SHORT).show(); }else{ infos.addAll(newData); notifyDataSetChanged(); } holder.showLoadMore(); } }); } }.start(); } }
ListView可以添加多种类型的显示条目,常见的有顶部的轮播图片,顶部下拉刷新,以及底部的加载更多等等。借助ViewHolder来管理ListView要显示的条目,代码更容易集中,可以针对不同的条目设计不同的Holder类。