2.4、系统控件不够用创建自定义控件

控件的和布局的集成结构:

所有的控件都是间接或者直接集成View的

所有的布局都是直接或者间接继承自ViewGroup的

View是Android种最基本的一种UI组件

可以再屏幕上进行创建任何布局或者各种事件

所以使用的各种控件其实就是再View的基础上添加了特有的功能

ViewGroup是一个特殊的View

他可以包含很对的子View和ViewGroup,是一个用于放置控件和布局的容器

当系统提供的控件不满足开发时,可以自己创建自定义的控件

1、引入布局

实现标题栏的代码进行解析

新建一个tittle.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"> <Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_margin="5dp"
android:text="back"
android:textColor="#fff"
android:background="#90a"
/>
<TextView
android:id="@+id/title_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight=""
android:gravity="center"
android:text="Title message"
android:textColor="#90a"
android:textSize="24sp"
/>
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_margin="5dp"
android:text="Edit"
android:textColor="#fff"
android:background="#90a"
/>
</LinearLayout>

这里使用android:background用于只当控件的背景(可以是图片可以是颜色)

android:layout_margin:用于指定控件再上下左右方向的便宜距离

效果:

再first_layout种进行使用这个标题:

此时直接使用<include>这个标签进行引用

<?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"> <include
layout="@layout/tittle"
/>
</LinearLayout>

同时还需要将系统自带的标题栏给隐藏

    @Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("FirstActivity====", String.valueOf(getTaskId()));
setContentView(R.layout.first_layout); ActionBar actionBar = getSupportActionBar();
if (actionBar != null
){
actionBar.hide();
}

}

使用getSupportActionBar()方法获得ActionBar的实例

再调用hide()方法进行隐藏

2、创建自定义的控件

引入布局的技巧解决了重复编写代码的问题

但是一个布局种有一些控件要求能够响应事件

还需要再每个活动中为这些控件单独的编写注册的代码

测试标题栏控件的实现:

新建类继承LinerLayout

public class Tittle extends LinearLayout {

    public Tittle(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.tittle,this); Button buttonBack = (Button) findViewById(R.id.title_back);
Button buttonEdit = (Button) findViewById(R.id.title_edit); buttonBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//退出
((Activity)getContext()).finish();
}
});
buttonEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(),"you click EDIT Button",Toast.LENGTH_LONG).show();
}
});
}
}

重写LinearLayout构造函数

在布局引入Tittle时就会调用这个函数

在构造函数中对标题栏进行动态加载

通过LayoutInflater的from()方法可以构建处一个LayoutInflater对象

然后调用inflate()方法可以动态加载一个布局文件,两个参数:

1、要加载布局文件的id

2、加载好布局在添加一个父布局

然后再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"> <com.example.ccrr.myapplication.Tittle
android:layout_width="match_parent"
android:layout_height="wrap_content">
</com.example.ccrr.myapplication.Tittle>
</LinearLayout>

需要指明控件的完整类名

点击BACK时退出

点击EDIT时出现提示信息

2.5、ListView

是Android中最长使用的控件之一

由于手机的屏幕有限,显示的数据内容不多,当有大量的数据需要展示的时候

可以使用ListView进行实现

类似QQ的好友列表...

1、简单实现

在first_layout中:

<?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"> <ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"></ListView>
</LinearLayout>

简单的加入该控件

MainActivityz中:

public class MainActivity extends AppCompatActivity {

    private String [] data = {"apple","Banana","Orange","Water",
"pear","Grape","pineapple","strawberry","cerry","Mango",
"","","","","","",""
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.firstlayout);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
} 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); }
}

使用数组提供数据进行显示

使用适配器ArrayAdapter来实现(指定类型)

有多个构造函数的重载

此时的参数:

1、当前的上下文

2、ListView的子布局id,这是Android内嵌的布局文件

3、数据

最后使用ListView的setAdapter()方法将构建好的适配器对象传进去

此时数据和ListView之间就建立了联系

2、定制界面

实现图片加数据的显示

定义一个实体类作为ListView的适配类型

public class Fruit {
//name:说过名字
private String name;
//商品的图片id位置
private int id;
public Fruit(String name, int id) {
this.name = name;
this.id = 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;
}
}

新建:

<?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:src="@drawable/qq"
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text_view"
android:layout_marginLeft="10dp"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content" /> </LinearLayout>

使用ImageView用于保存图片

使用TextView用于显示水果的名称

自定义一个适配器继承ArrayAdapter,并将泛型指定为Fruit类

public class FruitAdapter extends ArrayAdapter<Fruit> {

    private int resourceId;

    public FruitAdapter(Context context,  int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId, objects);
resourceId=textViewResourceId;
} @NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position);//获取当前项Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false); ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
TextView textView = (TextView) view.findViewById(R.id.text_view); imageView.setImageResource(fruit.getId());
textView.setText(fruit.getName()); return view;
}
}

重写父类的一组构造函数,用于将上下文、ListView子项布局的id和数据都传进来

由重写geiView()方法,将每个子项被滚动到屏幕内的时候会被调用

在方法中首先得到当前的Fruit的实例,然后再LayoutInflater来为这个子项目加载到我们传入的布局

第三个参数:指定为false表示只让我们在父布局中声明的layout属性生效,但不为这个View添加父布局

因为一旦有了父布局之后,他就不能再添加到ListView中。

再View中findViewById()方法分别用于获取ImageView和TextView的实例,并且调用他们的

setImageResource()和setText()方法来设置图片和文字

此时自定义的适配器就完成了

再MianActivity中

public class MainActivity extends AppCompatActivity {private List<Fruit> fruitList = new ArrayList<>();

    private void initFruit(){
for (int i =;i<;i++){
Fruit apple = new Fruit("Apple1",R.drawable.qq);
fruitList.add(apple); Fruit apple1 = new Fruit("Apple2",R.drawable.qq);
fruitList.add(apple1); Fruit apple2 = new Fruit("Apple3",R.drawable.qq);
fruitList.add(apple2); Fruit apple3 = new Fruit("Apple4",R.drawable.qq);
fruitList.add(apple3); Fruit apple4 = new Fruit("Apple5",R.drawable.qq);
fruitList.add(apple4); Fruit apple5 = new Fruit("Apple6",R.drawable.qq);
fruitList.add(apple5); Fruit apple6 = new Fruit("Apple7",R.drawable.qq);
fruitList.add(apple6);
} } @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.firstlayout);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
} initFruit(); FruitAdapter adapter = new FruitAdapter(
MainActivity.this,R.layout.fruit_item,fruitList); ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}

这里使用initFruit()进行初始化数据,数据可能来源于网络和数据库中。

初始化时将图片和名字传入到实例中。

然后将适配器传入ListView中即可进行显示,

此时定制的页面比较简单,只要修改对应的文件内容就可以制作出各种复杂的界面。

3、提升ListView的运行效率

对于ListView很难使用的原因时他可以有很多的细节可以进行优化

运行效率就是重要之一

目前使用的ListView的运行效率是比较低的

FruitAdaper的getView()方法中,每次都将布局重新加载一遍

当ListView快速滚动的时候就会成为性能的瓶颈

仔细观察可以看出getView()方法中还有一个参数convertView

这个参数用于将之前加载好的布局进行缓存,以便重用

package com.example.ccrr.myapplication.empty;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView; import com.example.ccrr.myapplication.R; import java.util.List; /**
* Created by ccrr on 2019/4/8.
*/ public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId, objects);
resourceId=textViewResourceId;
} @NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position);//获取当前项Fruit实例
//View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
View view;
if (convertView ==null){
view=LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
}else {
view =
convertView;
}
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
TextView textView = (TextView) view.findViewById(R.id.text_view); imageView.setImageResource(fruit.getId());
textView.setText(fruit.getName()); return view;
}
}

修改上述的代码,重新运行!

这里再getView()中进行判断

如果为null,则使用LayoutInflater去加载布局

不为null,则直接对convertView进行重用

这就大大的提高了效率

现在的代码还能进行优化

此时不会再重复去加载布局

但是每次再geiVIew()方法中会调用View的findViewByID()方法来获取一次控件的实例

此时可以借助ViewHolder对这部分进行优化

package com.example.ccrr.myapplication.empty;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView; import com.example.ccrr.myapplication.R; import java.util.List; /**
* Created by ccrr on 2019/4/8.
*/ public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId, objects);
resourceId=textViewResourceId;
} @NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position);//获取当前项Fruit实例
ViewHolder viewHolder;
View view; if (convertView ==null){
view=LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.imageView = (ImageView) view.findViewById(R.id.image_view);
viewHolder.textView = (TextView) view.findViewById(R.id.text_view); view.setTag(viewHolder);
}else {
view = convertView;
viewHolder= (ViewHolder) view.getTag();
} viewHolder.imageView.setImageResource(fruit.getId());
viewHolder.textView.setText(fruit.getName()); return view;
} class ViewHolder{
ImageView imageView;
TextView textView;
}

}

新增一个内部类ViewHolder用于对控件进行实例缓存

同理再if中进行判断

用View的setTag()方法将其存入View中

再有缓存时使用getTag()方法取出

4、ListView的点击事件

上述的ListView只是视觉效果,并没有点击的用途

此时实现其点击事件

public class MainActivity extends AppCompatActivity {private List<Fruit> fruitList = new ArrayList<>();

    private void initFruit(){
for (int i =;i<;i++){
Fruit apple = new Fruit("Apple1",R.drawable.qq);
fruitList.add(apple); Fruit apple1 = new Fruit("Apple2",R.drawable.qq);
fruitList.add(apple1); Fruit apple2 = new Fruit("Apple3",R.drawable.qq);
fruitList.add(apple2); Fruit apple3 = new Fruit("Apple4",R.drawable.qq);
fruitList.add(apple3); Fruit apple4 = new Fruit("Apple5",R.drawable.qq);
fruitList.add(apple4); Fruit apple5 = new Fruit("Apple6",R.drawable.qq);
fruitList.add(apple5); Fruit apple6 = new Fruit("Apple7",R.drawable.qq);
fruitList.add(apple6);
} } @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.firstlayout);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
} initFruit(); FruitAdapter adapter = new FruitAdapter(
MainActivity.this,R.layout.fruit_item,fruitList); ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter); //点击事件
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注册一个监听器

当用户点击任何一个子项时

就会回调onItemClick()方法

这个方法中通过position参数判定用户点击是哪一个子项

然后获得响应的事件

此时是打印处结果

2、Android-UI(自定义控件&ListView)的更多相关文章

  1. Android UI学习 - ListView (android.R.layout.simple_list_item_1是个什么东西)

    Android UI学习 - ListView -- :: 标签:Android UI 移动开发 ListView ListActivity 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始 ...

  2. Android UI组件----ListView列表控件详解

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  3. Android UI 之 ListView

    一.在代码中创建(不适用XML布局文件) 1.创建一个项目:ListViewLearn 2.修改MainActivity,继承于ListActivity 3.创建一个String数组,用来保存List ...

  4. Android UI设计

    Android UI设计--PopupWindow显示位置设置 摘要: 当点击某个按钮并弹出PopupWindow时,PopupWindow左下角默认与按钮对齐,但是如果PopupWindow是下图的 ...

  5. Android UI组件----自定义ListView实现动态刷新

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/3 ...

  6. Android UI编程之自定义控件初步——ImageButton

    我想我们在使用一些App的时候,应该不会出现一些“裸控件”的吧.除非是一些系统中的软件,那是为了保持风格的一致性,做出的一些权衡.我这里并非是在指责Android原生的控件不好看,说实在的,我很喜欢A ...

  7. Android UI:ListView -- SimpleAdapter

    SimpleAdapter是扩展性最好的适配器,可以定义各种你想要的布局,而且使用很方便. layout : <?xml version="1.0" encoding=&qu ...

  8. Android UI ListView的使用

    一.ListView的理解  1.什么ListView?   一种用来显示多个可滑动项(Item)列表的的ViewGroup 需要使用Adapter将集合数据和每一个Item所对应的布局动态适配到Li ...

  9. 【Android UI】Android ListView详解

    在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示.抽空把对ListView的使用做了整理,并写了个小例子,如下图. 列表的显示需要三 ...

  10. Android开发学习之路--UI之ListView

    这里再学习写android的ListView,其实我们都使用过ListView,就像手机的联系人,就是用的ListView了.下面就实现下简单的ListView吧,首先是xml文件中添加相关的代码: ...

随机推荐

  1. vs2015中的数据库架构对比工具(New Schema Comparison)

    大家都知道VS里的功能多到你根本没用过,今天来说说这个New Schema Comparison,他能做的事情就是在vs中对比我们两个数据库的架构.结构,并且能够更新过去或者生成脚本. Step.1( ...

  2. socket 和 webscoket 的区别

    Socket和WebSocket的来源 Socket Socket大致是指在端到端的一个连接中,这两个端叫做Socket.对于IT从业者来说,它往往指的是TCP/IP网络环境中的两个连接端,大多数的A ...

  3. 设置centos7.3的YUM源为国内阿里云源

     CentOS系统更换软件安装源 第一步:备份你的原镜像文件,以免出错后可以恢复. mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...

  4. spring mybatis 关于 basepackage 和 mapperLocations 的通配符匹配实例

    SqlSessionFactoryBean mapperLocations 注意下面几点 classpath* mapperLocation 起始路径不能有 * ,如 dm* 就不行 ** list ...

  5. visualvm 插件 visual gc 使用介绍

    visual gc 是 visualvm 中的图形化查看 gc 状况的插件. 具体详细介绍可参照: http://www.oracle.com/technetwork/java/visualgc-13 ...

  6. sql server web管理软件

    Sql server目前虽然没有mysql用户量大,但是微软的产品在易用性方面还是很不错的,有些政务类的项目还是用 Sql server数据库的, 目前有一款Sql server的web管理工具Tre ...

  7. django框架中form表单Post方法无法提交 Forbidden (403) CSRF verification failed. Request aborted.

    问题如图: 解决方法: 在视图函数中引入并使用装饰器 from django.views.decorators.csrf import csrf_exempt @csrf_exempt

  8. 洛谷P4781 【模板】拉格朗日插值(拉格朗日插值)

    题意 题目链接 Sol 记得NJU有个特别强的ACM队叫拉格朗,总感觉少了什么.. 不说了直接扔公式 \[f(x) = \sum_{i = 1}^n y_i \prod_{j \not = i} \f ...

  9. PHP 如何向关联数组指定的 Key 之前插入元素

    PHP 关联数组可以通过三种方式插入新元素: $array[$insert_key] = $insert_value; $array = array_merge($array, $insert_arr ...

  10. 搭建高可用mongodb集群(一)——配置mongodb

    在大数据的时代,传统的关系型数据库要能更高的服务必须要解决高并发读写.海量数据高效存储.高可扩展性和高可用性这些难题.不过就是因为这些问题Nosql诞生了. NOSQL有这些优势: 大数据量,可以通过 ...