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層,所以要減少層次,刪除無用佈局
- 學會使用相對佈局。佈局結構要清晰,選擇合適的佈局
- 組合控件
- 一些有用的屬性
- 佈局如何引用相同的部分,可以提取出來然後
</include>
重用佈局文件 <merge/>
減少視圖層級<ViewStub/>
需要是才加載,介紹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<String> adapter1 =
new ArrayAdapter<String>(this,R.layout.array_item,arr1);
//4
mListView1.setAdapter(adapter1);
}
}
- 讓Activity繼承ListActivity來實現
- 創建ArrayAdapter對象之後,直接使用
setListActivity(adapter)
設置該窗口顯示列表
- 創建ArrayAdapter對象之後,直接使用
public class MainActivity extends ListActivity{
@override
public void onCreate(Bundle saveIdnstanceState){
supert.onCreate(savedInstanceState);
String[] arr = {"劉詩詩", "趙麗穎", "楊冪"};
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(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<Map<String,Object>> listItems = new ArrayList<Map<String, Object>>();
for (int i = 0 ; i < names.length ; i++){
Map<String , Object> listItem = new HashMap<String, Object>();
listItem.put("header" ,imageId[i]);
listItem.put("name" , names[i]);
listItem.put("describe" , describe[i]);
listItems.add(listItem);
}
//3
SimpleAdapter simpleAdapter = new SimpleAdapter(this ,
listItems ,R.layout.simple_item ,
new String[]{"header","name","describe"} ,
new int[]{R.id.header,R.id.name,R.id.desc});
ListView listView =(ListView) findViewById(R.id.mylist);
//4
listView.setAdapter(simpleAdapter);
Intent intent = getIntent();
if (intent != null) {
String string = intent.getStringExtra(SplashActivity.TITLE);
setTitle(string);
}
}
}
- 擴展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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">
<GridView
android:id="@+id/grid01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:numColumns="4"
android:gravity="center"/>
<ImageSwitcher
android:id="@+id/switcher"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_gravity="center_horizontal"
android:inAnimation="@android:anim/fade_in"
android:outAnimation="@android:anim/fade_out"/>
</LinearLayout>
- cell.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="50dp"
android:layout_height="50dp"
/>
</LinearLayout>
- 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<Map<String,Object>> listItems = new ArrayList<Map<String, Object>>();
for (int i = 0 ; i < imageIds.length ; i++){
Map<String,Object> listItem = new HashMap<String, Object>();
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:
1. ScrolView瞭解不是很多,需要進一步去了解
2. ListView很重要,和BaseAdapter搭配起來,天生一對
3. 佈局應快要學完了,16.7.23