說說ListView,Percent佈局以及RecyclerView

文化可以用四句話來表達:植根於內心的修養,無須提醒的自覺,以約束爲前提的自由,爲他人着想的善良。那麼,你還覺得自己是個有文化的人嗎?我是凡人,所以需要努力。

  1. android常用控件和佈局的繼承機構

  2. 新佈局 百分比佈局

  3. ListView的使用和優化

  4. RecyclerView的使用

重用控件和佈局的繼承結構

結構繼承

新佈局 Percent佈局

android常用佈局使用的是LinearLayout,RelativeLayout,FrameLayout等,細心的話可以發現LinearLayout中的屬性android:weight其實類似於百分比,但是對於RelativeLayoutFrameLayout卻沒有這種功能,因此百分比佈局也就是在RelativeLayoutFrameLayout的基礎上面做了擴展,提供PercentFrameLayoutPercentRelativeLayout

爲了兼容所有版本的手機,android團隊將百分比佈局定義在了support庫中,所以需要在build.gradle中加入庫依賴

問題:在
查詢percent

查詢,你根本找不到Percent依賴提示,那麼這裏整理了幾個

根據你的開發對應版本:

compile 'com.android.support:percent:22.2.0'

compile 'com.android.support:percent:23.2.0'

compile 'com.android.support:percent:24.2.1'

親自測試的實踐問題:

對於使用Percent的佈局結構,因爲它是以父控件進行參考的,所以對於你的父類佈局一定要做到心中有數。

舉一個簡單的例子:

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentRelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_height="match_parent">


    <TextView
        android:id="@+id/tv_1"
        app:layout_widthPercent="50%"
        app:layout_heightPercent="50%"
        android:background="@color/colorAccent"
        android:text="我佔據50%"
        android:gravity="center"
        />
</android.support.percent.PercentRelativeLayout>

說明:

由於百分比佈局並不是內置在系統的SDK中,所以需要把完整的包路徑寫下來進行使用,接下來還需要定義一個app的命名空間,這樣才能使用百分比佈局的自定義屬性。app這種命名空間,在5.0的設計中Material Design中經常使用,後面我會進行整理。

因爲不屬於系統內置SDK,所以使用

app:layout_widthPercent="50%"
app:layout_heightPercent="50%"

這個的時候一定要你親自手寫,編譯軟件並不會進行任何的提示。

看效果圖:

百分比佈局的效果圖

ListView

使用ListView的時候除了實例化控件,聲明對象等等,還需要進行最重要的適配,就需要用到Adapter,請查看adaper參考文章,我個人認爲還是寫的很詳細。

那在這裏對於ListView要進行整理說明的是優化的問題:大多數的情況,開發出來的APP都是自定義的界面,並實現BaseAdapter中的方法,以外賣軟件爲例,商家的展示界面爲列表,每一家的信息相當於一個Item,這個界面坦白講不是很複雜但也不是特別的容易。所以ListView的優化很重要:

1.對於ListView適配機制來講,有多少條數據,就需要進行多少次的getView()方法,每次都將局部重新加載一次。
2.當ListView快速滾動的時候,你程序的性能會受到挑戰,用戶體驗下降。

其實在網上隨便百度一下,前輩都進行了整理,而且講的肯定比我詳細,我這裏只是進一步說明爲什麼這麼做。進行過優化的適配器,會有如下代碼


@override
public View getView(int position,View convertView,ViewGroup parent){
View view;
if(convertView == null){

    view = LayoutInflater.from(getContext()).inflate(layoutId,parent,false);

}else{
    view = convertView;
}

//下面的代碼

return view;
}

添加判斷語句,如果convertView爲null,那麼我們去加載佈局,如果不爲null,我們直接進行重用就好了。

進一步優化:

對於實例化的時候使用findViewById()來講也是在不斷獲取實例,影響性能,所以處理的方法是在Adaper中增加內部類,用於對控件的實例進行緩存。

代碼大致如下

@override
public View getView(int position,View convertView,ViewGroup parent){
View view;
//聲明內部類
ViewHolder viewHolder;
if(convertView == null){
    //當convertView爲null的時候,創建 ViewHolder類
    viewHolder = new ViewHolder();

    view = LayoutInflater.from(getContext()).inflate(layoutId,parent,false);
//實例化控件
viewHolder.textView = (TextView)view.findViewById(R.id.xxxxxxxx);

......

//之後將ViewHolder存儲在View中

view.setTag(viewHolder);

}else{
    view = convertView;
    //重新獲取ViewHolder實例
    viewHolder = (ViewHolder)view.getTag();
    }

//下面的代碼
...
//進行Ui更新的使用方法
viewHolder.textView.setText("char");
return view;

}

//創建內部類
class ViewHolder {
//聲明兩個控件
public TextView textView;

public ImageView imageView;

}

至此ListView的優化已經非常不錯了,你不相信的話看看下面的RecyclerView就可以感受到。

最後說說ListView的點擊事件,調用的 是ListView中的setOnItemClickListenter方法

listView.setOnItemClickListerner(new Adapter.OnItemClickListener(){
@override
public void onItemClick(AdaperView<?> parent,View view,int position,long id){

/**
* 對於這四個參數,有必要好好了解
* @params view 點擊的View
* @params position 點擊的第幾個控件
* @params id 這個每次輸出出來跟position的值是一樣的
*/
//執行你需要的操作
.....

}
});

以上是對ListView的總結,由於其強大的功能,在過去的android開發中可以說是貢獻卓越,直到今天還有不計其數的程序繼續使用着。但是需要進行優化來提升運行效率。ListView的擴展性不是特別的好,它只能實現數據縱向滾動的效果,如果你的需求是希望佈局橫向滾動,那麼你就要使用HorizontalScrollView進行擴展等等。因此,Android提供新的滾動控件RecyclerView,我們來看看。


更強大的RecyclerView

android加載大量數據 的新貴RecyclerView可以說是集萬千寵愛,
爲了使的RecyclerView能夠在所有的android手機中應用,android團隊將RecyclerView定義在了suppprt庫當中,所以想要使用這個控件,跟百分比佈局一樣,進行庫依賴。

//依賴你自己所需要的版本
compile 'com.android.support:recyclerview-v7:23.0.1'

compile 'com.android.support:recyclerview-v7:24.2.1'

依賴完成之後,我們開始進行使用

1.創建RecycleViewActivity以及相應的佈局文件activity_recycleview.xml

<?xml version="1.0" encoding="utf-8"?>
<!--佈局 activity_recycleview.xml-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycleView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</LinearLayout>

2.現在實現一個和ListView一樣的效果。

step1:創建item_view.xml佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">


    <!--圖片-->
    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <!--信息-->
    <TextView
        android:id="@+id/tv_info"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:textColor="@color/colorAccent"/>

</LinearLayout>

step2:爲RecyclerView撰寫適配器(重點)

對於RecyclerView而言,我們不需要做過多的優化,下面來看看:

/**
 * Created by welive on 2017/2/18.
 * 
 * 創建RecyclerView適配器的基本操作以及需要重寫的方法
 * 
 * 1.創建RecyclerViewAdapter繼承自RecycleView.Adapter<>,傳入的參數爲我們定義的內部類RecyclerViewAdapter.ViewHolder
 *  
 * 2.我們定義的內部類RecyclerViewAdapter.ViewHolder繼承自RecyclerView.ViewHolder
 * 
 * 3.RecyclerViewAdapter.ViewHolder必須要實現一個帶有參數View的構造函數,而這個View代表RecyclerView子項的最外層的佈局
 *    對於toString()方法可以寫也可以不寫(隨意)
 * 
 * 4.之後需要重寫onBindViewHolder(),onCreateViewHolder(),getItemCount()方法
 * 
 * 
 */

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    /**
     * 把需要顯示的數據源傳進來
     */
    public RecyclerViewAdapter() {
    }


    static class ViewHolder extends RecyclerView.ViewHolder {

        public ViewHolder(View itemView) {
            super(itemView);
        }

        @Override
        public String toString() {
            return super.toString();
        }
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }

    @Override
    public int getItemCount() {
        return 0;
    }
}

下面我的來書寫需要的內容

  • 我們需要一個Fruit的對象類,裏面含有水果圖片Id,還有水果的名稱

新建類 FruitClass


public class FruitClass {

    private String name;
    private int id;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}
  • 將數據源傳遞給適配器,構造函數修改如下
    //講傳入進來的數據源賦值給一個全局變量
    private List<FruitClass> mFruitList;
    public RecyclerViewAdapter(List<FruitClass> fruitList) {
        mFruitList = fruitList;
    }
  • 修改onCreateViewHolder()方法
//該方法是用來創建ViewHolder實例的
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

//將佈局文件加載進來
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view,parent,false);
        //將佈局傳遞給ViewHolder
        ViewHolder viewHolder = new ViewHolder(view);
        //返回實例
        return viewHolder;
    }
  • 內部類ViewHolder的構造函數
TextView tv_info;
ImageView iv_image;
//實例化控件
public ViewHolder(View itemView) {
 super(itemView);
 tv_info = ((TextView) itemView.findViewById(R.id.tv_info));
 iv_image = ((ImageView) itemView.findViewById(R.id.iv_image));
}
  • 對控件進行賦值
@Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        holder.iv_image.setImageResource(mFruitList.get(position).getId());
        holder.tv_info.setText(mFruitList.get(position).getName());

    }
  • 返回適配的次數
@Override
    public int getItemCount() {
        return mFruitList.size();
    }

所以現在我們的適配器算是完成了,看看下面的

step3:在Activity中對RecyclerView進行使用,先看看代碼

//實例化控件
RecyclerView recyclerView = ((RecyclerView) findViewById(R.id.recycleView));
//佈局Manager,RecyclerView的特別之處
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
//實例化適配器
RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(initFruits());
//設置適配器
recyclerView.setAdapter(recyclerViewAdapter);

適配器中顯示的數據

public List<FruitClass> initFruits(){

        List<FruitClass> fruitClassList = new ArrayList<>();

        for (int i = 0;i<2;i++){
            FruitClass fruitClass0 = new FruitClass();
            fruitClass0.setId(R.mipmap.ic_launcher);
            fruitClass0.setName("apple");
            fruitClassList.add(fruitClass0);

            FruitClass fruitClass1 = new FruitClass();
            fruitClass1.setId(R.mipmap.ic_launcher);
            fruitClass1.setName("banana");
            fruitClassList.add(fruitClass1);

            FruitClass fruitClass2 = new FruitClass();
            fruitClass2.setId(R.mipmap.ic_launcher);
            fruitClass2.setName("pear");
            fruitClassList.add(fruitClass2);

            FruitClass fruitClass3 = new FruitClass();
            fruitClass3.setId(R.mipmap.ic_launcher);
            fruitClass3.setName("grape");
            fruitClassList.add(fruitClass3);

            FruitClass fruitClass4 = new FruitClass();
            fruitClass4.setId(R.mipmap.ic_launcher);
            fruitClass4.setName("cheer");
            fruitClassList.add(fruitClass4);
        }
        return  fruitClassList;
    }

好了,我們看了以上的使用,和ListView其實很是類似,除了LinearLayoutManager這個也是RecyclerView的特別之處

RecyclerView能夠實現強大的擴展功能,就是因爲recylerView在使用的時候需要設置setLayoutManager(LayoutManager layout)屬性

        /**
         * LayoutManager layout 
         * 
         * 1.LinearLayoutManager  爲縱向,(默認的)
         * 2.LinearLayoutManager  並設置linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL)爲橫向
         * 3.StaggeredGridLayoutManager(int spanCount, int orientation),瀑布流佈局,當orientation爲VERTICAL參數spanCount表列數,當orientation爲HORIZONTAL參數spanCount表示行數
         * 4. GridLayoutManager(Context context, int spanCount) ,網格佈局 spanCount 表示列數
         * 
         */
recyclerView.setLayoutManager(LayoutManager layout);

下面會對這四種Manager進行實踐

LinearLayoutManager VERTICAL

縱向佈局

LinearLayoutManager HORIZONTAL

/**
*1.修改爲橫向
*linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
*
*2.將相應的將RecyclerView加載的佈局修改爲縱向,寬度固定
*/
橫向

GridLayoutManager

//修改佈局管理器

GridLayoutManager gridLayoutManager = new GridLayoutManager(this,3);
recyclerView.setLayoutManager(gridLayoutManager);

網格佈局

StaggeredGridLayoutManager

/**
* 使用這種佈局,修改佈局管理器爲StaggeredGridLayoutManager
* 另外將數據源修改,是內容參差不齊
*/

StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(staggeredGridLayoutManager);

縱向的瀑布流

在來修改一次,令瀑布流個事爲橫向

StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.HORIZONTAL);

橫向的瀑布流

對於這一部分的示例,請在個人的github中下載
https://github.com/wedfrendwang/PrivateProject.git

並切換至分支:recyclerViewUnit


附:製作Nine-Path圖片

android支持加載Nine-Path圖片,當然我們也可以自己製作

1.在Android sdk 目錄下有個tools文件夾

2.找到draw9patch.bat文件

3.要打開該文件,需要將你的jdk的bin目錄配置到環境變量path中

如果你是用的是 AndroidStudio,需要將你的androidstudio的安裝目錄/jre/bin配置上去就好


終於整理完成了,禮拜六的你是否也一樣在拼搏,充實着自己。爲什麼要這麼辛苦?或許,我們終其一生的努力,只爲了成爲一個體面的普通人吧!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章