1 布局与优化
1.1 五大布局
- LinearLayout:线性布局
- orientation:vertical:垂直的,horizontal:水平的
- weight:设置比重时,layout_width="0"。weightSum总比重。例如:微信底部四个tab平分宽带,可以使其weight 1:1:1:1
- RelativeLayout:相对布局
- xmlns:xml的命名空间
- layout_alignParentRight:与布局容器的右边对齐
- layout_alignParentBottom:位于父容器的底部
- layout_alignLeft:与给出id组件的左边对齐
- layout_above/toRightOf:给出id组件的上方/右边
- layout_marginTop/toRightOf:外边距
- layout_paddingRight:内边距
- FrameLayout:帧布局,一层一层叠加起来
- AbsoluteLayout:绝对布局
- TableLayout:表格布局
- TableRow
1.2 布局优化
- 减少布局层次的重要性层次过多会影响到性能
- 官方建议布局层次--最多10层,所以要减少层次,删除无用布局
- 学会使用相对布局。布局结构要清晰,选择合适的布局
- 组合控件
- 一些有用的属性
- 布局如何引用相同的部分,可以提取出来然后
重用布局文件
-
减少视图层级 -
需要是才加载,介绍ViewStub代码 ,介绍ViewStub文字,两篇结合来看。ViewStub指向的布局文件在多数情况下并不会被显示出来,只会在某种特殊的情况下对ViewStub进行inflate操作,而且这种操作只能进行一次,此时会将ViewStub替换掉,变成显示所指向的布局文件。,一旦替换后,此时原来的布局文件中就没有ViewStub控件了,这就好像ViewStub只是为其所指向的布局占了一个位子,需要时才显示 - 小技巧
- 不要嵌套多个使用layout_weight属性的LinearLayout
- Android lint :删除无用的资源,布局,类,引用
- HierarchyViewer:分析性能及其优化
2 无比重要的ListView
- AdapterView是一个容器,把很多的列表项以合适的形式显示出来,而列表项的内容和格式可以用Adapter指定,调用AdapterView的
setAdapter(Adapter)
方法设置Adapter即可。
2.1四种设置Adapter的方法:(以ListView为例子)
- 使用ArrayAdapter设置
- 告诉大家我要创建列表项了,初始化这个控件
- 定义了一个数组,该数组是为多个列表项提供了数据
- 创建
ArrayAdapter(Context,textViewResource,数组或者List)
对象。其中Context代表访问应用的接口,一般是this。textViewResource代表一个资源的ID,该资源分ID是指定了每个列表项的组件,等于为每个列表项指定了格式。后面的数据就按照组件的格式传入。 - 最后为该ListView设置Adapter
public class ArrayAdapterActivity extends Activity{
ListView mListView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_arrayadapter);
//1
mListView1 = (ListView) findViewById(R.id.listview1);
//2
String[] arr1 = {"王俊凯" ,"王源","易烊千玺"};
//3
ArrayAdapter adapter1 =
new ArrayAdapter(this,R.layout.array_item,arr1);
//4
mListView1.setAdapter(adapter1);
}
}
- 让Activity继承ListActivity来实现
- 创建ArrayAdapter对象之后,直接使用
setListActivity(adapter)
设置该窗口显示列表
public class MainActivity extends ListActivity{
@override
public void onCreate(Bundle saveIdnstanceState){
supert.onCreate(savedInstanceState);
String[] arr = {"刘诗诗", "赵丽颖", "杨幂"};
ArrayAdapter adapter1 = new ArrayAdapter(this, R.layout.item, arr);
setListAdapter(adapter);
}
}
- 使用SimpleAdapter
- 前面都是创建提供列表内容的数组
- 创建一个List集合,集合元素是Map,把前面的内容数组封装成一个List集合
- 创建SimpleAdapter对象。后面有5个参数,第一个是Context。第二个是一个元素是Map的List集合,每个Map对象生成一个列表项。第三个参数是指定界面布局的ID。第四个是一个String[]对象的参数,决定提取Map中那些key对应的value来生成列表项。第五个参数是对应于value填充的组件,该组件是来源与第三个参数的布局。是int[]类型的参数
- 设置Adapter
public class MainActivity extends AppCompatActivity {
//1
private String[] names = new String[]{"lisa" , "linda" , "july" , "anna"};
private String[] describe = new String[]{"a cute child" , "a beautiful girl" , "a smart student" , "a handsome boy"};
private int[] imageId = new int[]{R.drawable.libai,R.drawable.nongyu,R.drawable.qingzhao,R.drawable.tiger};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//2
List
- 扩展BaseAdapter实现 ,需要重写4个方法
- int getCount():返回值控制Adapter会有多少个列表项
- Object getItem(int i):返回第i处的列表项的内容
- getItemId(int i):返回第i除列表项的id
- View getView(int i, View view, ViewGroup viewGroup):返回第i除列表项的组件
BaseAdapter baseAdapter = new BaseAdapter() {
@Override
public int getCount() {
//指定40个选项
return 40;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
LinearLayout linearLayout = new LinearLayout(MainActivity.this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
ImageView imageView = new ImageView(MainActivity.this);
imageView.setImageResource(R.mipmap.ic_launcher);
TextView text = new TextView(MainActivity.this);
text.setText("this is" + i + "listview");
text.setTextSize(20);
linearLayout.addView(imageView);
linearLayout.addView(text);
return linearLayout;
}
};
2.2 优化
- 不必每次都要加载视图,只需要第一次的时候加载,所以可以加个判断
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder;
//优化
if(view == null){
view = mLayoutInflater.inflate(R.layout.activity_items,null);
viewHolder = new ViewHolder();
//获取控件
viewHolder.phone_name = (TextView) view.findViewById(R.id.item_name);
viewHolder.phone_age = (TextView) view.findViewById(R.id.item_age);
viewHolder.phone_image = (ImageView) view.findViewById(R.id.item_image);
view.setTag(viewHolder);
}else {
viewHolder = (ViewHolder) view.getTag();
}
//数据绑定,mInfoList是一个类型为用户的List,该用户有Age和Name属性
viewHolder.phone_name.setText(mInfoList.get(i).getmName());
viewHolder.phone_age.setText(String.valueOf(mInfoList.get(i).getmAge()));
viewHolder.phone_image.setImageResource(R.mipmap.ic_launcher);
return view;
}
- 设置类来保存所加载视图的控件
class ViewHolder{
TextView phone_name;
TextView phone_age ;
ImageView phone_image ;
}
- 所以只有第一次加载的时候,会去加载视图获取控件,当前视图不为空时,只会去获取视图里控件,节约内存。
2.3 item不同怎么办,getItemViewType()
- 推荐一篇写的好而且我看的懂的博客Adapter的getViewTypeCount()和getItemViewType()
- 微信的聊天列表
- 聊天框使用.9图,用getItemViewType()设置不同的ListView
- 小demo非正式仿聊天界面
2.4 风格不同的分割线
- ListView的 android:divider属性来设置,所以可以用自定义的Drawable来设置分割线的风格
3 GridView和ScrollView
3.1 GridView与ListView的相似之处
- 需要设置Adapter
- 它们俩的parent都实现了AdapterView
3.2 GridView的常用实现
- 常用属性:
- android:numColums:设置列数
- android:horizontalSpacing:设置各元素之间的水平间距
- android:verticalSpacing:设置各元素之间的垂直间距
- android:gravity:设置对齐方式
- 使用了SimpleAdapter,ImageSwitcher是图片切换器,在切换ImgeView时使用动画
- activity_main.xml
- cell.xml
- java源代码
package com.example.w.myapplication;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import android.widget.ViewSwitcher;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
GridView gridView;
ImageSwitcher imageSwitcher;
int[] imageIds = new int[] {
R.drawable.bomb5,R.drawable.bomb6,R.drawable.bomb7,R.drawable.bomb8,
R.drawable.bomb9,R.drawable.bomb10,R.drawable.bomb11,R.drawable.bomb12,
R.drawable.bomb13,R.drawable.bomb14,R.drawable.bomb15,R.drawable.bomb16,
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridView = (GridView)findViewById(R.id.grid01);
//创建一个List对象,List对象的元素是Map
List> listItems = new ArrayList>();
for (int i = 0 ; i < imageIds.length ; i++){
Map listItem = new HashMap();
listItem.put("image" , imageIds[i]);
listItems.add(listItem);
}
//为ImageSwitcher提供一个ViewFactory,由其生成View
imageSwitcher = (ImageSwitcher)findViewById(R.id.switcher);
imageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
@Override
public View makeView() {
//创建ImageView对象
ImageView imageView = new ImageView(MainActivity.this);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setLayoutParams(new ImageSwitcher.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
return imageView;
}
});
SimpleAdapter simpleAdapter = new SimpleAdapter(this , listItems ,R.layout.cell
,new String[]{"image"},new int[]{R.id.imageView});
gridView.setAdapter(simpleAdapter);
//列表被单击
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
imageSwitcher.setImageResource(imageIds[i]);
Toast.makeText(MainActivity.this,"图片" + i +"被点击了" , Toast.LENGTH_LONG).show();
}
});
//列表被选中
gridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> adapterView, View view, int i, long l) {
imageSwitcher.setImageResource(imageIds[i]);
Toast.makeText(MainActivity.this,"图片" + i +"被选中了" , Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView> adapterView) {
}
});
}
}
3.3 ScrollView
- 最多只能包含一个组件,或只支持垂直滚动,若需要水平滚动,则可借助另一个滚动视图-HorizontalScrollView
你可看可不看,但我必须得看的Tips:
- ScrolView了解不是很多,需要进一步去了解
- ListView很重要,和BaseAdapter搭配起来,天生一对
- 布局应快要学完了,16.7.23