3. 軟件也要拼臉蛋-UI開發(fā)的點點滴滴

1.jpg

一.常用控件的使用方法

1.TextView

<TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="24sp" android:textColor="#00ff00" android:text="This is TextView"/>

match_parent 由父布局來決定當前控件的大小。
wrap_content 由控件的內(nèi)容決定當前控件的大小。
**android:gravity: **來指定文字的對齊方式,可選值有top,bottom,left,right,center等,可以用“|”來同時指定多個值,這里我們指定的center,效果等同于center_vertical|center_horizontal.表示文字在垂直和水平方向都居中對齊。
**android:textSize: **指定文字的大小,在Android中字體大小使用sp作為單位。
**android:textColor: **指定文字的顏色。
(#2button)2.Button
<Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button" android:textAllCaps="false"/>

android:textAllCaps="false"系統(tǒng)會對Button中的所有英文字母自動進行大小寫轉(zhuǎn)換,使用這個配置可以禁用這一默認的屬性。
3.EditText
<EditText android:id="@+id/edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Type something here" android:maxLines="2" />

**android:hint: **指定了一段提示性的文本。
**android:maxLines: **指定了EditText的最大行數(shù)為兩行,這樣當輸入的內(nèi)容超過兩行時,文本就會向上移動,而EditText則不會在繼續(xù)拉伸。
String inputText = editText.getText().toString(); Toast.makeText(MainActivity.this, inputText, Toast.LENGTH_SHORT).show();

調(diào)用EditText的getText()方法獲取到輸入的內(nèi)容,再調(diào)用toString()方法轉(zhuǎn)換成字符串。
4.ImageView
項目中有一個空的drawable目錄,不過由于這個目錄沒有指定具體的分辨率,所以一般不使用它來放置圖片,這里我們在res目錄下新建一個drawable-xhdpi目錄。
<ImageView android:id="@+id/image_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/w"/>

**android:src: **給imageView指定了一張圖片。
imageView.setImageResource(R.drawable.m);

調(diào)用ImageView的setImageResource()方法將顯示的圖片給成m.
5.ProgressBar
ProgressBar用于在界面上顯示一個進度條,表示我們的程序正在加載一些數(shù)據(jù)。

image

如何才能讓進度條在數(shù)據(jù)加載完成時消失呢?
Anbroid控件的可見屬性。所有的Android控件都具有這個屬性,可以通過android:visibility進行指定,可選值有三種:visible,invisible和gone。visible表示控件是可見的,這個值是默認值,不指定android:visibility時控件都是可見的。invisible表示控件不可見,但是他仍然占據(jù)著原來的位置和大小??梢岳斫獬煽丶兂赏该鳡顟B(tài)了。gone則表示控件不僅不可見,而且不在占用任何屏幕空間。我們還可以通過代碼來設置控件的可見性,使用的是setVisibility()方法,可以傳入View.VISIBLE,View.INVISIBLE,View.GONE這三種值。
if (progressBar.getVisibility() == View.GONE) { progressBar.setVisibility(View.VISIBLE); } else { progressBar.setVisibility(View.GONE); }

getVisibility()方法來判斷ProgressBar是否可見,如果可見就將ProgressBar隱藏掉,如果不可見就將ProgressBar顯示出來。
<ProgressBar android:id="@+id/progress_bar" android:layout_width="match_parent" android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal" android:max="100" />

我們還可以給ProgressBar指定不同的樣式,剛剛是圓形進度條,通過style屬性可以將它指定成水平進度條。
**android:max: **給進度條設置一個最大值,然后在代碼中動態(tài)的更改進度條的進度。
int progress = progressBar.getProgress(); progress = progress + 10; progressBar.setProgress(progress);

每點擊一次按鈕,我們就獲取進度條的當前進度。
6.AlertDialog
AlertDialog可以在當前的界面彈出一個對話框,這個對話框是置于所有界面元素之上的,能夠屏蔽掉其他控件的交互能力。
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle("This is Dialog"); dialog.setMessage("something inportant"); dialog.setCancelable(false); dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }); dialog.show();

首先通過AlertDialog.Builder創(chuàng)建一個AlertDialog的實例,然后可以為這個對話框設置標題,內(nèi)容,可否取消等屬性,接下來調(diào)用setPositiveButton()方法為對話框設置確定按鈕的點擊事件,調(diào)用setNegativeButton()方法設置取消按鈕的點擊事件,最后調(diào)用show()方法將對話框顯示出來。
7.ProgressDialog
ProgressDialog會在對話框中顯示一個進度條,一般用于表示當前操作比較耗時,讓用戶耐心等待。
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setTitle("This is ProgressDialog"); progressDialog.setMessage("Loading..."); progressDialog.setCancelable(true); progressDialog.show();

注意setCancelable()中傳入了false,表示ProgressDialog是不能銅鼓back鍵來取消掉的,這時你就一定要在代碼中做好控制,當數(shù)據(jù)加載完成后必須要調(diào)用ProgressDialog的dismiss()方法來關閉對話框,否者ProgressDialog將會一直存在。
二.詳解四種基本布局
布局是一種可用于放置很多控件的容器,它可以按照一定的規(guī)律調(diào)整內(nèi)部控件的位置,從而編寫出精美的界面,當然布局的內(nèi)部除了放置控件外,也可以放置布局,通過多層布局的嵌套,我們就能夠完成一些比較復雜的界面實現(xiàn)。
1.線性布局
LinearLayout:線性布局,是一種非常常用的布局。這個布局會將他所包含的控件在現(xiàn)行方向上依次排列。
android:orientation="vertical"

**android:orientation: **指定排列的方向。如果不指定,默認的排列方向就是horizontal.
如果LinearLayout的排列方向是horizontal,內(nèi)部的控件就絕對不能將寬度指定為match_parent。因為這樣的話,單獨一個控件就會將整個水平方向占滿,其他的控件就沒有可放置的位置了。同樣的道理,如果LinraeLayout的排列方向是vertical,內(nèi)部的控件就不能將高度指定為match_parent.
**android:gravity: **用于指定文字在控件中的對齊方式。
**android:layout_gravity: **指定控件在布局中的對齊方式。注意的是,當LinearLayout的排列方向是horizontal時,只有垂直方向上的對齊方式才會生效,因為此時水平方向上的長度是不固定的,每添加一個控件,水平方向上的長度都會改變,因而無法指定該方向上的對齊方式。同樣的道理,當LinearLayout的排列方向是vertical時,只有水平方向上的對齊方式才會生效。
android:layout_weight=""

android:layout_weight= 允許我們使用比例的方式來指定控件的大小。它在手機屏幕適配性方面可以起到非常重要的作用。
dp:是Android中用于指定控件大小,間距等屬性的單位。
2.相對布局
RelativeLayout:相對布局,它可以通過相對定位的方式讓控件出現(xiàn)在布局的任何位置。
android:layout_alignParentLeft="true"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:layout_alignParentBottom="true"android:layout_centerInParent="true"

上面每個控件都是相對于父布局進行定位的。
android:layout_above="@id/button3"android:layout_below="@id/button3"android:layout_toLeftOf="@id/button3"android:layout_toRightOf="@id/button3"

android:layout_above=“ ”:讓一個控件位于另一個控件的上方。需要為這個屬性指定相對控件id的引用。
android:layout_below="@id/button3" :讓一個控件位于另一個控件的下方。
android:layout_toLeftOf="@id/button3" :讓一個控件位于另一個控件的左側(cè)。
android:layout_toRightOf="@id/button3" :讓一個控件位于另一個控件的右側(cè)。
注意:當一個控件去引用另一個控件的ID時,該控件一定要定義在引用控件的后面,不然會出現(xiàn)找不到ID的情況。
android:layout_alignLeft="@id/button3"android:layout_alignRight="@id/button3"android:layout_alignTop="@id/button3"android:layout_alignBottom="@id/button3"

android:layout_alignLeft="@id/button3" :讓一個控件的左邊緣和另一個控件的左邊緣對齊。
android:layout_alignRight="@id/button3" :讓一個控件的右邊緣和另一個控件的右邊緣對齊。
android:layout_alignTop="@id/button3" :讓一個控件的頂部與另一個控件的頂部對齊。
android:layout_alignBottom="@id/button3" :讓一個控件的底部與另一個控件的底部對齊。
3.幀布局
FrameLayout:幀布局這種布局沒有方便的定位方式,所有的控件都會默認排放在布局的左上角。
4.百分比布局
Android引入了一種全新的布局方式----百分比布局。在這種布局中我們可以不再使用wrap_content,match_parent等方式來指定控件的大小,而是允許直接指定控件在布局中所占的百分比,這樣的話就可以輕松實現(xiàn)平分布局甚至是任意比例分割布局的效果了。
由于LinearLayout本身已經(jīng)支持按比例指定控件的大小,因此百分比布局只為FrameLayout和RelativeLayout進行了功能擴展,提供了PercentFrameLayout和PercentRelativeLayout這兩個全新的布局。
Android團隊將百分比布局定義在了support庫當中,我們只需要在項目的build.gradle中添加百分比布局庫的依賴,就能保證百分比布局在Android所有系統(tǒng)版本上的兼容性了。
<android.support.percent.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button1" android:text="Button 1" android:layout_gravity="left|top" app:layout_widthPercent="50%" app:layout_heightPercent="50%"/> <Button android:id="@+id/button2" android:text="Button2" android:layout_gravity="right|top" app:layout_widthPercent="50%" app:layout_heightPercent="50%"/> <Button android:id="@+id/button3" android:text="Button3" android:layout_gravity="left|bottom" app:layout_widthPercent="50%" app:layout_heightPercent="50%"/> <Button android:id="@+id/button4" android:text="Button4" android:layout_gravity="right|bottom" app:layout_widthPercent="50%" app:layout_heightPercent="50%"/></android.support.percent.PercentFrameLayout>

最外層我們使用了PercentFrameLayout,由于百分比布局并不是內(nèi)置在系統(tǒng)SDK中的,所以需要把完整的包路徑寫出來,然后還必須定義一個app的命名空間,這樣才能使用百分比布局的自定義屬性。
不過PercentFrameLayout還是會繼承FrameLayout的特性,即所有的控件默認都是擺放在布局的左上角。
三.系統(tǒng)控件不夠用?創(chuàng)建自定義控件

image

我們所用的所有控件都是直接或間接繼承自View的,所用的所有的布局都是直接或間接繼承自ViewGroup的,View是安卓中最基本的一種UI組件,它可以在屏幕上繪制一塊矩形區(qū)域,并能響應這塊區(qū)域的各種事件,因此,我們使用的各種控件其實就是在View的基礎之上有添加了各自特有的功能,而ViewGroup則是一種特殊的View,他可以包含很多子View和子ViewGroup,是一個用于放置控件和布局的容器。
1.引入布局
<include layout="@layout/title"/>

android:background : 用于為布局或控件指定一個背景,可以使用顏色或圖片來進行填充。
android:layout_margin :指定控件在上下左右方向上的偏移距離。
ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.hide(); }

getSupportActionBar()方法來獲得ActionBar的實例,然后在調(diào)用ActionBar的hide()方法將標題欄隱藏起來。
2.創(chuàng)建自定義控件
public class TitleLayout extends LinearLayout{ public TitleLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title,this); }}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.uilayouttest.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content"> </com.example.uilayouttest.TitleLayout></LinearLayout>

我們重寫了LinearLayout中帶有兩個參數(shù)的構(gòu)造函數(shù),在布局中引入TitleLayout控件就會調(diào)用這個構(gòu)造函數(shù),然后在構(gòu)造函數(shù)中需要對標題欄布局進行動態(tài)加載,這就要借助LayoutInflater來實現(xiàn)了,通過LayoutInflater的from()函數(shù)可以構(gòu)建出一個LayoutInflater對象,然后調(diào)用inflate()方法就可以動態(tài)加載一個布局文件,inflate()方法接收兩個參數(shù),第一個參數(shù)是要加載的布局文件的id,第二個參數(shù)是給加載好的布局在添加一個父布局。
添加自定義控件和添加普通控件的方式基本是一樣的,只不過在添加自定義控件的時候,我們需要指明控件的完整類名,包名在這里是不可以省略的。
public class TitleLayout extends LinearLayout{ Button titleBack,titleEdit; public TitleLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title,this); initView(); initEvent(); } public void initView() { titleBack = (Button) findViewById(R.id.title_back); titleEdit = (Button) findViewById(R.id.title_edit); } public void initEvent() { titleBack.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ((Activity) getContext()).finish(); } }); titleEdit.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show(); } }); }}

上面是自定義控件的點擊事件。
四.最常用和最難用的控件——ListView
1.ListView的簡單用法
ListView絕對可以稱得上是Android中最常用的控件之一,幾乎所有的應用程序都會用到它,由于手機屏幕空間有限,能夠一次性在屏幕上顯示的內(nèi)容并不多,當我們的程序中有大量的數(shù)據(jù)需要展示的時候,就可以借助ListView來實現(xiàn)。
private String[] data = { "Apple","Banana","Orange","Watermelon", "Pear","Grape","Pineapple","Strawberry","Cherry","Mango", "Apple","Banana","Orange","Watermelon", "Pear","Grape","Pineapple","Strawberry","Cherry","Mango" };

ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1,data); ListView listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter);

Android中提供了很多適配器的實現(xiàn)類,其中我認為最好用的就是ArrayAdapter.它可以通過泛型來指定要適配的數(shù)據(jù)類型,然后在構(gòu)造函數(shù)中把要適配的數(shù)據(jù)傳入。ArrayAdapter有多個構(gòu)造函數(shù)的重載,你應該根據(jù)實際情況選擇最合適的一種.
在ArrayAdapter的構(gòu)造函數(shù)中依次傳入當前上下文,ListView子項布局的id,以及要適配的數(shù)據(jù)。注意:我們使用了android.R.layout.simple_list_item_1作為ListView子項布局的id,這是一個Android內(nèi)置的布局文件,里面只有一個TextView,可用于簡單的顯示一段文本。
最后,還需要調(diào)用ListView的setAdapter()方法,將構(gòu)建好的適配器對象傳遞進去,這樣ListView和數(shù)據(jù)之間的關聯(lián)就建立完成了。
2.定制ListView的界面
public class FruitAdapter extends ArrayAdapter<Fruit>{ private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) { super(context,textViewResourceId,objects); resourceId = textViewResourceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view = LayoutInflater.from(getContext()).inflate(resourceId, parent,false); ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; }}

FruitAdapter重寫了父類的一組構(gòu)造函數(shù),用于將上下文,ListView子項布局的id和數(shù)據(jù)都傳遞進來,又重寫了getView()方法,這個方法在每個子項被滾動到屏幕內(nèi)的時候會被調(diào)用。在getView()方法中首先通過getItem()方法得到當前項的Fruit實例,然后使用LayoutInflater來為這個子項加載我們傳入的布局。
這里LayoutInflater的inflate()方法接收三個參數(shù),前兩個參數(shù)我們已經(jīng)知道是什么了,第三個參數(shù)指定成false,表示只讓我們在父布局中聲明的layout屬性生效,但不為這個View添加父布局,因為一旦View有了父布局之后,他就不能再添加到ListView中了。
private void initFruits() { for (int i = 0;i < 2;i++) { Fruit apple = new Fruit("Apple",R.mipmap.ic_launcher); fruitList.add(apple); Fruit banana = new Fruit("Banana",R.mipmap.ic_launcher); fruitList.add(banana); Fruit orange = new Fruit("orange",R.mipmap.ic_launcher); fruitList.add(orange); Fruit watermelon = new Fruit("watermelon",R.mipmap.ic_launcher); fruitList.add(watermelon); Fruit pear = new Fruit("pear",R.mipmap.ic_launcher); fruitList.add(pear); Fruit grape = new Fruit("grape",R.mipmap.ic_launcher); fruitList.add(grape); Fruit pineapple = new Fruit("pineapple",R.mipmap.ic_launcher); fruitList.add(pineapple); Fruit strawberry = new Fruit("strawberry",R.mipmap.ic_launcher); fruitList.add(strawberry); Fruit cherry = new Fruit("cherry",R.mipmap.ic_launcher); fruitList.add(cherry); Fruit mango = new Fruit("mango",R.mipmap.ic_launcher); fruitList.add(mango); } }

用于初始化所有的水果數(shù)據(jù),在Fruit類的構(gòu)造函數(shù)中將水果的名字和對應的圖片ID傳入,然后把創(chuàng)建好的對象添加到水果列表中。
3.提升ListView的運行效率
在FruitAdapter的getView()方法中,每次都將布局重新加載了一遍,當ListView快速滾動的時候,這就會成為性能的瓶頸。
getView()方法中還有一個convertView參數(shù),這個參數(shù)用于將之前加載好的布局進行緩存,以便以后可以重用。
@Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent,false); }else { view = convertView; } ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image); TextView fruitName = (TextView) view.findViewById(R.id.fruit_name); fruitImage.setImageResource(fruit.getImageId()); fruitName.setText(fruit.getName()); return view; }

我們在getView()方法中進行了判斷,如果convertView為null,則使用LayoutInflater去加載布局,如果不為null,則直接對convertView進行重用,這樣就大大提高了ListView的運行效率。在快速滾動的時候也可以表現(xiàn)出更好的性能。
雖然現(xiàn)在已經(jīng)不回去在重復加載布局,但是每次在getView()方法中還是會調(diào)用View的findViewById()方法來獲取一次控件的實例。我們可以借助一個ViewHolder來對這部分性能進行優(yōu)化。

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Fruit fruit = getItem(position);
        View view;
        ViewHolder viewHolder;
        if (convertView == null) {
            view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
            viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder); //將ViewHolder存儲在View中// 
        } else {
            view = convertView;
            viewHolder = (ViewHolder) view.getTag(); //重新獲取ViewHolder 
        }
        viewHolder.fruitImage.setImageResource(fruit.getImageId());
        viewHolder.fruitName.setText(fruit.getName());
        return view;
    }

class ViewHolder {
    ImageView fruitImage;
    TextView fruitName;
}

我們新增了一個內(nèi)部類ViewHolder,用于對控件的實例進行緩存,當convertView為null的時候,創(chuàng)建一個ViewHolder對象,并將控件的實例都存放在ViewHolder里,然后調(diào)用View的setTag()方法,將ViewHolder對象存儲到View中,當convertView不為null的時候,則調(diào)用View的getTag()方法,把ViewHolder重新取出,這樣所有控件的實例都緩存在了ViewHolder里,就沒有必要每次都通過findViewByid()方法來獲取控件實例了。
4.ListView的點擊事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Fruit fruit = fruitList.get(position); Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show(); } });

使用setOnItemClickListener()方法為ListView注冊了一個監(jiān)聽器,當用戶點擊了ListView中的任何一個子項時,就會回調(diào)onItemClick()方法。

五,更強大的滾動控件--RecyclerView

ListView的性能比較差,ListView的擴展性也不夠好,它只能實現(xiàn)數(shù)據(jù)縱向滾動的效果,如果我們想實現(xiàn)橫向滾動的話,ListView是做不到的。
Android團隊采取了和百分比布局同樣的方式,將RecyclerView定義在了support庫當中。
新建FruitAdapter類,讓這個適配器繼承自RecyclerView.Adapter,并將泛型指定為FruitAdapter.ViewHolder。其中,ViewHolder是我們在FruitAdapter中定義的一個內(nèi)部類。

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
    private List<Fruit> mFruitList;

    public FruitAdapter(List<Fruit> fruitList) {
        mFruitList = fruitList;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        Fruit fruit = mFruitList.get(position);
        holder.fruitImage.setImageResource(fruit.getImageId());
        holder.fruitName.setText(fruit.getName());
    }

    @Override
    public int getItemCount() {
        return mFruitList.size();
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View itemView) {
            super(itemView);
            fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image);
            fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
        }
    }
}

先定義了一個內(nèi)部類ViewHolder,ViewHolder要繼承自RecyclerView.ViewHolder。然后ViewHolder的構(gòu)造函數(shù)中要傳入一個View參數(shù),這個參數(shù)通常就是RecyclerView子項的最外層布局。那么我們就可以通過findViewById()方法來獲取到布局中的ImageView和TextView的實例了。
FruitAdapter中也有一個構(gòu)造函數(shù),這個方法用于把要展示的數(shù)據(jù)源傳進來,并賦值給一個全局變量mFruitList,我們后續(xù)的操作都將在這個數(shù)據(jù)源的基礎上進行。
由于FruitAdapter是繼承自RecyclerView.Adapter的,那么就必須重寫onCreateViewHolder(),onBindViewHolder()和getItemCount()這三個方法,
onCreateViewHolder()方法是用于創(chuàng)建ViewHolder實例的,我們在這個方法中將fruit_item布局加載進來,然后創(chuàng)建一個ViewHolder()實例,并把加載進來的布局傳入到構(gòu)造函數(shù)當中,最后將ViewHolder的實例返回。
onBindViewHolder()方法是用于對RecyclerView子項的數(shù)據(jù)進行賦值的,會在每個子項被滾動到屏幕內(nèi)的時候執(zhí)行,這里我們通過position參數(shù)得到當前項的Fruit實例,然后再將數(shù)據(jù)設置到ViewHolder的InageView和TextView當中即可。
getItemCount()方法就非常簡單了,它用于告訴RecyclerView一共有多少子項,直接返回數(shù)據(jù)源的長度就可以了。

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
    LinearLayoutManager layoutManager = new LinearLayoutManager(this); 
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL); 
    recyclerView.setLayoutManager(layoutManager); 
    FruitAdapter adapter = new FruitAdapter(fruitList); 
    recyclerView.setAdapter(adapter);

在onCreate()方法中我們先獲取到RecyclerView的實例,然后創(chuàng)建了一個LinearLayoutManager對象,并將它設置到RecyclerView當中,LayoutManager用于指定RecyclerView的布局方式,這里使用的LinearLayoutManager是線性布局的意思,可以實現(xiàn)和ListView類似的效果。
2.實現(xiàn)橫向滾動和瀑布流布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

調(diào)用LinearLayoutManager的setOrientation()方法來設置布局的排列方式,默認是縱向排列的,我們傳入LinearLayoutManager.HORIZONTAL表示讓布局橫行排列,這樣RecyclerView就可以橫向滾動了。
ListView的布局排列是由自身去管理的,而RecyclerView則將這個工作交給了LayoutManager,LayoutManager中制定了一套可擴展的布局排列接口,子類只要按照接口的規(guī)范來實現(xiàn),就能定制出各種不同排列方式的布局了。
除了LinearLayoutManager之外,RecyclerView還給我們提供了GridLayoutManager和StaggeredGridLayoutManager這兩種內(nèi)置的布局排列方式,GridLayoutManager可以用于實現(xiàn)網(wǎng)格布局,StaggeredGridLayoutManager可以用于實現(xiàn)瀑布流布局。
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager);

StaggeredGridLayoutManager的構(gòu)造函數(shù)接收兩個參數(shù),第一個參數(shù)用于指定布局的列數(shù),傳入3表示會把布局分為3列,第二個參數(shù),用于指定布局的排列方向,傳入StaggeredGridLayoutManager.VERTICAL表示會讓布局縱向排列。
3.RecyclerView的點擊事件
ListView在點擊事件上 的處理并不人性化,setOnitemClickListener()方法注冊的是子項的點擊事件,但如果我想點擊的是子項里具體的某一個按鈕呢?雖然ListView也是能做到的,但是實現(xiàn)起來就相對比較麻煩了,為此,RecyclerView干脆直接摒棄了子項點擊事件的監(jiān)聽器,所有的點擊事件都有具體的View去注冊,就在沒有這個困擾了。
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.fruit_item,parent,false); final ViewHolder holder = new ViewHolder(view); holder.fruitView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(v.getContext(), "You click view" +fruit.getName(), Toast.LENGTH_SHORT).show(); } }); holder.fruitImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(v.getContext(), "You clicked image" +fruit.getName(), Toast.LENGTH_SHORT).show(); } }); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { Fruit fruit = mFruitList.get(position); holder.fruitImage.setImageResource(fruit.getImageId()); holder.fruitName.setText(fruit.getName()); } @Override public int getItemCount() { return mFruitList.size(); } class ViewHolder extends RecyclerView.ViewHolder { ImageView fruitImage; TextView fruitName; View fruitView; public ViewHolder(View itemView) { super(itemView); fruitView = itemView; fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image); fruitName = (TextView) itemView.findViewById(R.id.fruit_name); } }

在ViewHolder中添加了fruitView變量來保存子項最外層布局的實例,然后在onCreateViewHolder()方法中注冊點擊事件就可以了。這里分別為最外層布局和ImageView都注冊了點擊事件,RecyclerView的強大之處也在這里,它可以輕松實現(xiàn)子項中任意控件或布局的點擊事件。我們在兩個點擊事件中先獲取了用戶點擊的position,然后通過position拿到相應的Fruit實例。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容