说说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配置上去就好


终于整理完成了,礼拜六的你是否也一样在拼搏,充实着自己。为什么要这么辛苦?或许,我们终其一生的努力,只为了成为一个体面的普通人吧!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值