布局
0、约束布局
1、线性布局(LinearLayout)
常见属性
以下属性为常见属性,除了最后一个。
1、组件名称:+id/
android:+id/name:代表声明一个新的元素
android:id/name:代表直接使用以及存在的元素
2、组件高宽:
android:layout_width
android:layout_height
1、属性值:
wrap_content 代表实际内容尺寸
match_parent 与父级元素尺寸
fill_parent 填充整个父级尺寸
2、属性值单位:
尺寸单位:dp
3、组件背景:backgroud
adnroid:backgroud
属性值:颜色代码、图片
4、同级元素或者与父控件距离:layout_margin*
android:layout_margin*
5、子元素之间距离:layout_padding*
android:layout_padding*
6、子元素排列方向:orientation
在父容器中设置android:orientation
属性值:
1、垂直:vertical
2、水行:horizontal
3、默认水平方向,左边排列
7、子元素对齐方式:grivity
在子元素中设置:android:grivity
比如在底部,垂直居中、右上角等,
8、子元素空间占比权重:layout_weight
子元素中设置:layout_weight
1、比如两个元素的高宽均为0dp,权重都为1,表示各种权重为1,各占50%的空间。
2、如果一个元素的宽为50dp,权重各为1,代表1元素先占50dp,剩余均分
9 一行显示:sigleLine
true即为一行显示
2、相对布局(RelativeLayout)
以下属性为常见属性。
1、在某元素左侧
android:layout_toLeftOf
2、在某元素右侧
android:layout_toRightOf
3、跟某元素的底部对齐
android:layout_alignBottom
4、在父元素底部对齐
android:layout_alignParentBottom
5、在谁的下面
android:layout_layout_below
其他控件
1. TextView
1、主要内容如下
1.文字大小
2.超出省略号
3.文字+icon
4.中划线-下划线
5.跑马灯
在布局中声明元素后,通过findViewById(R.id.元素id)
现在实现个按钮点击后,实现如上TextView文字效果。
2.1、第一步:
在布局文件中,声明一个button,id是btn_textView,然后在acitivity中创建点击事件。
//声明button变量
private Button mbtnTextView;
@override
protected void onCreate(Bunle saveInstanceSate){
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
mbtnTextView = (Botton)findViewById(R.id.btn_textView)
//单击事件
mbtnTextView。setOnClikeListener(new View.OnClikListener){
@override
public void onClik(View v){
//跳转到TextView
}
};
)
}
2.2、第二步:
创建一个新的TextView activity作为独立界面,androidMainFest.xml注册。并继续在button单击事件中添加如下代码:
Intent intent = new Intent(当前activity类名.this,TextViewactivity.class);
startActivity(intent)
2.3、第三步:
修改TextViewTextView.xml布局,增加一个TextView组件。常见属性如下:
android:text 是文本
android:textColor 颜色
android:textSize 字体大小,单位sp
android:ellipsize="end" 超出尺寸文本用...代替。
android:drawableRight="@drawable/icon_xx" 给文本右侧设置一个图片
android:drawablePadding 文字与图片距离
3、中划线、下划线需要在代码中设置:
tv = findViewById(R.id.tv4)
tv.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
//去锯齿
tv.getPaint().setAntAlias(true)
4、跑马灯效果:
android:singleLine=true
android:ellipsize=marquee
android:marqueeRepeatLimit="marquee_foever"
android:focusable=true 焦点才能一直有效果
android:focusableIntochModel=true
2. button
1、圆角button
在drawable创建一个drawable resouce file 文件bg_btn,root element选择share
android:shape 图形属性
android:color 填充颜色
<corners android:radius='5dp'/> 圆角
然后将button的backgroud设置为"@drawable/bg_btn"
2、描边button
在drawable创建一个drawable resouce file 文件bg_bt2
<stroke android:width="1dp"
android:color="#ffccc"/>
然后将button的backgroud换掉即可.
3、button按压效果
<item android:state_pressed="true">
<share>
<solid android:color="#ff9900"/>
<corners android:radius="5dp"/>
</share>
</item>
<item android:state_pressed="false">
<share>
正常的效果
</share>
</item>
4、按钮点击弹窗
在单击事件里:
Toast.makeText(aitive.this,'文本',Toast.LENGTH_SHORT)
3.EditText
1、常见属性
默认EditText是只有下边框的.如果要自定义,需要自建drawable下建立 drawable resouce file文件.
密码框,其他属性与一般ui相同.
<EditText
android:hint="密码"
android:inputType="textPassword"
android:maxLine=1
android:drawableLeft="图标"
andrlid:drawablePadding="5dp"
/>
如果是数字,只需inputType设置为number.
2、 文本变化监听事件
EditText.andTextChangedListener(new View.OnClikListener){
@override
public beforeTextChange(){
//改变之前
}
@override
public onTextChange(CharSequence s,int start,int before,int count){
//改变之后
//CharSequence是当前输入的文字
//日志打印
Log.d("input",s.toString())
}
@override
public afterTextChange(){
//改变之后
}
};
)
4.单选:RadioButton
1、常见属性
<RadioGroup>
<RadioButton
android:id
android:layout_width
android:layout_height
android:text='男'
android:check="true" //默认选中,必须有id
android:orientation="" //方向
android:button="@null" //去掉单选小圆圈
android:backgroupd="@drawable/select" //自定义样式
/>
</RadioGroup>
2、select:自定义样式
<selector>
<share android:state_checked="true">
选中效果
</share>
</item>
<item android:state_checked="false">
<share>
正常的效果
</share>
</selector>
3、监听事件
m=findViewById(R.id.rg1)
m.setOnclickChangeListener(new RadioGroup.OncheckkedChangeListener(){
public void onCheckedChange(RadioGroup group,@IDres int checkedId){
//选中的redio
RadioButton = group.findViewById(checkedId)
Toast.make(本activity.this,"",Tost.Lentgh_short).show();
}
});
5.UI自定义样式
<shape>
<solid android:color="背景色"/>
<!--边框设计-->
<stroke android:width="边框粗细" android:color="边框颜色"/>
<!--圆角设计-->
<corners
android:bottomLeftRadius="10sp图形左下角圆角"
android:topLeftRadius="10sp"
android:bottomRightRadius="10sp"
android:topRightRadius=""
/>
<!--颜色渐变-->
<gradient
android:startColor="开始颜色"
android:endColor="结速颜色"
android:centerColor="过度颜色"
android:angle="渐变方向"
android:type="linear渐变方式"
/>
</shape>
渐变方向:
0:从左向右渐变
90:从下向上渐变
180:从右向左渐变
270:从上向下渐变
6.复选框
7.ImageView
ImageView是图片组件.文件通常存储在drawable开头的目录下.不同分辨率的图片存储在不同以drawable开头的目录下.创建一个临时的drawable-xhdpi,复制图片进去.初始的图片设定有android:src="@drawable/图片名称".宽度及高度使用wrap_content,表明根据实际情况来设定.
代码修改图片:
imageView = (ImageView)findViewById(R.id.image_name)
imageView.setImageRrsource(R.drawable.image_name)
8.ProgressBar
原型的加载进度条.加载万,通过控件的可见属性设置即可.可见属性有三种可选:
android:visibility=visible/invisible/gone
visible是可见,默认值;invisible是不可见,但仍然占据位置;gone是不可见,不占用屏幕空间.可以通过如下方法设定:
a.setVisiblebility(View.VISIBLE\View.INVISIBLE\View.GONE)
9.AlertDialog
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity4.this);
dialog.setTitle("对话框");
dialog.setMessage("要回传的数据:你好");
//释放点击对话框外部的屏幕关闭对话框
dialog.setCancelable(false);
//确认按钮的逻辑
dialog.setPositiveButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity4.this,"确认1",Toast.LENGTH_LONG).show();
}
});
//取消按钮的逻辑
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(MainActivity4.this,"取消",Toast.LENGTH_LONG).show();
}
});
//显示对话框
dialog.show();
//finish()
另外需要注意的是,dialog不是阻塞运行的,dialog.show()后面的代码会继续运行.
11.progressDialog加载对话框
是加载对话框,数据完成后,需要手动dialog.dismiss()关闭,不然会一直存在.
12.自定义控件
UI空间都是继承子View,布局都是继承ViewGroup.
view是一种基本空间,在屏幕上划分一块矩形区域,能响应矩形区域内的各种事件.Viewgrup是一种特殊控件,包含不少view和子ViewGROUP.
创建一个自定义title
- 自定义UI及配置
自定义一个通用的top bar.就像苹果的title,包括back和exit按钮.
首先创建一个布局,起名为title. 里面为相对布局,增加两个按钮,一个是back一个是exit.back靠top左,exit靠top 右.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:textSize="20sp"
android:layout_alignParentLeft="true"
android:text="back" />
<Button
android:id="@+id/button_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_alignParentRight="true"
android:text="exit"
android:textSize="20sp" />
</RelativeLayout>
然后在其他action的布局文件中,增加如下配置:
<include layout="@layout/title"></include>
同时在oncreate()代码中隐藏action自带的top bar:
ActionBar bar=getSupportActionBar();
bar.hide();
- 给布局增加事件
自此,自定义title组件可以看到效果了.但是back和exit的事件需要在每个action写相同的代码,这样很不好.
我们可以通过继承linearlayout,绑定title ui布局文件.
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
Button back = findViewById(R.id.button_back);
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Activity) getContext()).finish();
}
});
}
}
在布局中替换上面的
<include layout="@layout/title"></include>
如下:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity4">
<com.example.myapplication.TitleLayout
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
13.ListView控件
1、简单的listview使用
listview出镜率非常高.本节演示一个只支持文本的listview.具体步骤如下:
1、创建一个ListViewActivity,在布局中增加listView
2、准备listView数据,用list保存
3、创建listView适配器,适配器将会在内部为数据创建子布局
4、listView设置适配器
1、创建ListViewActivity
创建一个ListViewActivity,并在对应的activity_list_view布局文件中增加listView组件.activity_list_view.xml布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".LlistViewActivity">
<ListView android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="87dp"
tools:layout_editor_absoluteY="84dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
通过布局可知,listView组件已经填充了整个布局文件.
下面在action里填充数据.
2、初始化数据
用循环生成了array数据,listview无法直接绑定数据,所以要说用ArrayAdapter适配器先处理数据.ListViewActivity.class:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_llist_view);
//数组填充数据
ArrayList data= new ArrayList();
for(int i=0;i<100;i++){
data.add(i+"x");
}
//数据适配器,指定了显示的action,以及listview里面的子布局
ArrayAdapter<String> adapter = new ArrayAdapter<String>(LlistViewActivity.this, android.R.layout.simple_list_item_1,data);
ListView lv = findViewById(R.id.list_view);
lv.setAdapter(adapter);
}
说明:
ArrayAdapter初始化参数共三个,第一个是当前action,第二个是子布局,第三个是单位.
listView本身其实也是容器,适配器通过指定的子布局进行组装数据,然后listview通过setAdapter(adapter)直接进行装载.
本文使用的内置布局android.R.layout.simple_list_item_1,就是一个简单TextView组件,适配器会根据数据动态的创建TextView用来显示数据.
2、listView显示图片
listView本身是一个容器,里面是子布局.所以要显示图片,我们需要创建一个布局,这个布局没有根容器,然后把子布局放入listView即可.
为了完成这个目标,我们需要做两件事:
1.自定义子布局
2.自定义实现适配器
1、 自定义listView子布局
子布局为右侧为图片,左侧为文字的list. 先用LinearLayout作为根布局,里面放一个图片组件、文本组件。默认横向排列。list_view_child_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">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/list_view_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</androidx.appcompat.widget.AppCompatImageView>
<TextView
android:id="@+id/list_view_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
>
</TextView>
</LinearLayout>
2、 创建list记录类
用来设置list的图片,文本。ResouceBean作为资源bean,存储图片.
ResouceBean.class:
public class ResouceBean {
private String name;//图片名称
private int imageId;//图片ID
public ResouceBean(String name, int imageId){
this.name=name;
this.imageId=imageId;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
2、 创建适配器
自定义适配器,将接受的数据与子布局进行组装。具体的步骤如下:
1、适配器继承自ArrayAdapter
2、初始化方法参数接收子布局ID
3、重写getView,进行动态装置数据,getView每次滚均会执行
4、
ImageTextAdapter.class
public class ImageTextAdapter extends ArrayAdapter<ResouceBean> {
private int child_layout_id;//子布局
public ImageTextAdapter(@NonNull Context context, int child_layout_id, @NonNull List<ResouceBean> objects) {
super(context, child_layout_id, objects);
this.child_layout_id =child_layout_id;
}
//该方法滚动到屏幕就会调用执行
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ResouceBean bean = getItem(position);
Log.d("ImageTextAdapter 图片ID:",bean.getImageId()+"");
//加载子布局,参数1是子布局id,参数2是根布局,参数3是此子布局自身不设置根布局,不然无法添加到listview
View child_layout = LayoutInflater.from(getContext()).inflate(child_layout_id,parent,false);
ImageView iv = child_layout.findViewById(R.id.list_view_image);
TextView text = child_layout.findViewById(R.id.list_view_text);
iv.setImageResource(bean.getImageId());
text.setText(bean.getName());
return child_layout;
}
}
适配器初始化,会接受子布局的Id.
getView()是滚动到屏幕就会调用执行,所以在里面装配子布局. 首先使用getItem()获取要显示的资源bean,然后使用LayoutInflater获得子布局,并且为里面的组件进行赋值.
其中inflate第三个参数是指不为此布局添加父布局,不然将会导致无法添加到listView中.完成设置后,返回子布局.
3、 绑定listView
在listview的ListViewActivity中绑定数据:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_llist_view);
//数组填充数据
List<ResouceBean> data = new ArrayList<ResouceBean>();
for(int i=0;i<100;i++){
ResouceBean bean = new ResouceBean("测试"+i,R.drawable.test);
data.add(bean);
}
//数据适配器,指定了显示的action,以及listview里面的子布局
ImageTextAdapter adapter = new ImageTextAdapter(this,R.layout.list_view_child_layout,data);
ListView lv = findViewById(R.id.list_view);
lv.setAdapter(adapter);
}
到此为止,已完成.
3、提升listview性能,优化适配器
在上面的例子中,listview的适配器的getView()方法,每次滚动都会执行,重写加载布局.当滚动快的时候,性能问题就来了.
在getView()方法中有个convertView参数,是对之前布局进行缓存的,可以重用. 所以每次在增加一个convertView的判断,如果不为空,直接将convertView 赋值给child_layout. 修改代码如下:
ImageTextAdapter.class
public class ImageTextAdapter extends ArrayAdapter<ResouceBean> {
private int child_layout_id;//子布局
public ImageTextAdapter(@NonNull Context context, int child_layout_id, @NonNull List<ResouceBean> objects) {
super(context, child_layout_id, objects);
this.child_layout_id =child_layout_id;
}
//该方法滚动到屏幕就会调用执行
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ResouceBean bean = getItem(position);
Log.d("ImageTextAdapter 图片ID:",bean.getImageId()+"");
#优先加载缓存子布局
View child_layout;
if(convertView==null){
child_layout = LayoutInflater.from(getContext()).inflate(child_layout_id,parent,false);
}else{
view=convertView
}
ImageView iv = child_layout.findViewById(R.id.list_view_image);
TextView text = child_layout.findViewById(R.id.list_view_text);
iv.setImageResource(bean.getImageId());
text.setText(bean.getName());
return child_layout;
}
}
虽然子布局进行了优化,但是每次findViewById()都会获取控件实例,我们是不是只用取一次就行了? 其实只要把findViewById()获取的实例存储起来,下次利用就好了.完整的适配器代码如下:
public class ImageTextAdapter extends ArrayAdapter<ResouceBean> {
private int child_layout_id;//子布局
public ImageTextAdapter(@NonNull Context context, int child_layout_id, @NonNull List<ResouceBean> objects) {
super(context, child_layout_id, objects);
this.child_layout_id =child_layout_id;
}
//该方法滚动到屏幕就会调用执行
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
ResouceBean bean = getItem(position);
Log.d("ImageTextAdapter 图片ID:",bean.getImageId()+"");
//子布局及布局的组件,convertView缓存了子布局
View child_layout;
//内部类,创建对象后存储起来
RecyclerViewHolder recyclerViewHodler;
if (convertView==null){
child_layout = LayoutInflater.from(getContext()).inflate(child_layout_id,parent,false);
recyclerViewHodler=new RecyclerViewHolder();
recyclerViewHodler.imageView=child_layout.findViewById(R.id.list_view_image);
recyclerViewHodler.textView=child_layout.findViewById(R.id.list_view_text);
child_layout.setTag(recyclerViewHodler);
}else {
child_layout=convertView;
}
recyclerViewHodler=(RecyclerViewHolder)child_layout.getTag();
ImageView iv = recyclerViewHodler.imageView;
TextView text =recyclerViewHodler.textView;
iv.setImageResource(bean.getImageId());
text.setText(bean.getName());
return child_layout;
}
class RecyclerViewHolder{
ImageView imageView;
TextView textView;
}
4、listView子布局组件点击事件
listView绑定适配器后,通过通过setOnItemClickListener设置监听事件.
ListViewActivity.class 的oncreate()完整代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_llist_view);
//数组填充数据
List<ResouceBean> data = new ArrayList<ResouceBean>();
for(int i=0;i<100;i++){
ResouceBean bean = new ResouceBean("测试"+i,R.drawable.test);
data.add(bean);
}
//数据适配器,指定了显示的action,以及listview里面的子布局
ImageTextAdapter adapter = new ImageTextAdapter(this,R.layout.list_view_child_layout,data);
ListView lv = findViewById(R.id.list_view);
lv.setAdapter(adapter);
//事件
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ResouceBean bean=data.get(position);
Toast.makeText(ListViewActivity.this,bean.getName(),Toast.LENGTH_SHORT).show();
}
});
}
14.滚动控件RecyclerView
1、listview效果及横向滑动
listview只能纵向滚动,不能横向滚动.andorid提供了一个更加大的控件recyclerView.
recylerView是listview增强版本,目前官方推荐使用recylerView.
要实现listview 图形+文字的同样效果,所以直接使用上面例子的子布局和资源.
1、创建RecylcerViewActivity及布局
创建RecylcerViewActivity及布局,布局中包括recylerview控件.
activity_recylcer_view.xml布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".RecylcerViewActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerViewid"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
RecylcerViewActivity.class先创建,等一下填充代码。
2、 创建适配器
RecylerViewAdapter.class代码:
public class RecylerViewAdapter extends RecyclerView.Adapter<RecylerViewAdapter.InnViewHolder> {
private List<ResouceBean> bean = new ArrayList<>();
static class InnViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;//list item图片
TextView textView;//list item文字
public InnViewHolder(@NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.list_view_image);
textView=itemView.findViewById(R.id.list_view_text);
}
}
public RecylerViewAdapter(List<ResouceBean> data){
bean=data;
Log.d(this.getClass().toString()+"初始化",data.size()+"");
}
@Override
public InnViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view_child_layout,parent,false);
InnViewHolder holder = new InnViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull InnViewHolder holder, int position) {
ResouceBean resb = bean.get(position);
Log.d(this.getClass().toString(),resb.getName()+">>>>");
holder.textView.setText(resb.getName());
holder.imageView.setImageResource(resb.getImageId());
}
@Override
public int getItemCount() {
return bean.size();
}
}
解释:
1.RecylerViewAdapter继承自RecyclerView.Adapter<RecylerViewAdapter.InnViewHolder>,其中RecylerViewAdapter.ViewHolder是该类的一个静态内部类.
2.bean存储传过来的图片,文本数据.
3.InnViewHolder是静态内部类,接受子布局,获取子布局控件对象.
4.RecylerViewAdapter构造函数接受传递过来的图片文本数据.
5.重写onCreateViewHolder,获取子布局,并传递给InnViewHolder内部类.
6.重写onBindViewHolder,给子布局控件设置图片及文字.
7.getItemCount获取数据的长度
需要注意的是,R.layout.list_view_child_layout子布局的跟布局一定要设置一个高度,或者选择高度选择wrap_content,不然一个item就会占满屏幕.
3、修改RecylcerViewActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recylcer_view);
//数组填充数据
List<ResouceBean> data = new ArrayList<ResouceBean>();
for(int i=0;i<100;i++){
ResouceBean bean = new ResouceBean("测试"+i,R.drawable.test);
data.add(bean);
}
RecyclerView recyclerView=findViewById(R.id.recyclerViewid);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//横向滑动
//layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
RecylerViewAdapter adapter = new RecylerViewAdapter(data);
recyclerView.setAdapter(adapter);
}
解释:
1.初始化数据,创建RecyclerView组件
2.给recyler布局创建一个布局管理器
3.将数据传递给适配器,与recyler适配
4.横向滑动:layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
RecyclerView布局切换
RecyclerView使用不同的布局管理器,很容易实现不同的展现效果.
//线性布局
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
//layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//网格布局
GridLayoutManager grild = new GridLayoutManager(this,2);
//grild.setOrientation(GridLayoutManager.HORIZONTAL);
//瀑布流布局
StaggeredGridLayoutManager sgrild= new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(sgrild);
recylerView事件
recylerView没有直接提供事件,而是子布局控件直接设置监听事件. recylerView的子布局是在adapter绑定子布局及获取控件的,所以直接在获取控件后,直接设置事件.
RecylerViewAdapter.class 修改onCreateViewHolder方法,控件增加事件的注册.
public class RecylerViewAdapter extends RecyclerView.Adapter<RecylerViewAdapter.InnViewHolder> {
private List<ResouceBean> bean = new ArrayList<>();
static class InnViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;//list item图片
TextView textView;//list item文字
public InnViewHolder(@NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.list_view_image);
textView=itemView.findViewById(R.id.list_view_text);
}
}
public RecylerViewAdapter(List<ResouceBean> data){
bean=data;
Log.d(this.getClass().toString()+"初始化",data.size()+"");
}
@Override
public InnViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_view_child_layout,parent,false);
InnViewHolder holder = new InnViewHolder(view);
//item点击事件
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Toast.makeText(v.getContext(),position+"----",Toast.LENGTH_SHORT).show();
}
});
//子布局控件事件
holder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//当前item
int position = holder.getAdapterPosition();
Toast.makeText(v.getContext(),bean.get(position).getImageId(),Toast.LENGTH_SHORT).show();
}
});
holder.textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Toast.makeText(v.getContext(),bean.get(position).getName(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull InnViewHolder holder, int position) {
ResouceBean resb = bean.get(position);
Log.d(this.getClass().toString(),resb.getName()+">>>>");
holder.textView.setText(resb.getName());
holder.imageView.setImageResource(resb.getImageId());
}
@Override
public int getItemCount() {
return bean.size();
}
}
解释:
- int position = holder.getAdapterPosition();获取到当前item
15.recylerView作为微信聊天UI
recylerView使用有点复杂,所以本例子主要目的是熟悉recylerView的使用流程.
1.总体布局:
微信的聊天UI上面部分是内容,用来显示聊天的内容,所以是个容器.下面是消息输入框和发送按钮.
UI布局思路,root布局为垂直布局,上部分为聊天的容器,使用recylerView,底部用线性布局,左侧一个输入框,右侧为发送按钮.
另外还需要一个子布局,用来显示每条消息.然后动态加入到recylerView中.
2.具体流程:
使用recylerView作为内容容器.通过发送按钮,将消息输入框的内容动态加入到list中,然后将数据传递个适配器,适配器将数据和消息记录子布局绑定,recylerView在绑定适配器,这样容器就会显示发送的消息.
下面是具体的实现:
1.创建MessageActivity,进行布局:
先不看MessageActivity代码,先看一下布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MessageActivity">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--用来显示消息-->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/messagebox"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<!--发送消息表单-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="80dp"
android:layout_width="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/message_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxLines="2"
/>
<com.google.android.material.button.MaterialButton
android:id="@+id/sendmessage_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"/>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
2.创建子布局:
然后在创建一个子布局message_item_layout:
子布局里面有一个线性布局,背景是Nine-Patch图片,是个消息框.里面包含一个文本控件.
<?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="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message">
<TextView
android:id="@+id/message_item"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="0dp"
android:paddingLeft="0dp"
android:layout_marginRight="10dp"
/>
</LinearLayout>
</LinearLayout>
Nine-Patch 图片是可以拉伸的图片,可以通过android studio创建,具体做法是选中一个图片,右键选择create-9-patch file.然后可以编辑.
具体的编辑是告诉android那边可以拉伸,哪些不能拉伸,可以拉伸的像素用边框点黑色的点.
上面的点:意思是横向拉伸会复制这个垂直的像素.
左侧的点:意思是纵向拉伸时,可以复制的横向条形像素.
下方的点:黑点连成的线条,意思是文本显示的宽度区域.
右侧的点:黑点连城的线条,意思是文本可以显示的高度区域.
3.创建适配器
我们的数据很简单,只是一个消息,字符串. 适配器必须继承自 RecyclerView.Adapter<MessageAdaptger.InnViewHolder>,其中InnViewHolde是个内部类,内部类用来初始化创建子布局的控件.
适配件内部创建一个list属性,用来存储消息.
然后通过onCreateViewHolder()来创建子布局,将子布局传递给InnViewHolder,InnViewHolder来完成子布局初始化.
通过onBindViewHolder()方法获取当前list中的记录,并且通过InnViewHolder类型的参数,来绑定消息.
具体代码如下:
public class MessageAdaptger extends RecyclerView.Adapter<MessageAdaptger.InnViewHolder> {
ArrayList<String> data =null;
public MessageAdaptger(ArrayList list){
data=list;
}
//完成子布局控件的创建
static class InnViewHolder extends RecyclerView.ViewHolder{
TextView text;
public InnViewHolder(@NonNull View itemView) {
super(itemView);
text=itemView.findViewById(R.id.message_item);
}
}
//完成子布局创建
@NonNull
@Override
public InnViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_item_layout,parent,false);
InnViewHolder holder = new InnViewHolder(view);
return holder;
}
//获取当前显示的list记录,并绑定到子布局控件中
@Override
public void onBindViewHolder(@NonNull InnViewHolder holder, int position) {
String resb =(String) data.get(position);
Log.d(this.getClass().toString(),resb+">>>>");
holder.text.setText(resb);
}
@Override
public int getItemCount() {
return data.size();
}
}
4.完善MessageActivity
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.util.ArrayList;
import java.util.List;
public class MessageActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
//保存数据
ArrayList<String> data = new ArrayList<String>();
//线性布局
RecyclerView messagebox= findViewById(R.id.messagebox);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
messagebox.setLayoutManager(layoutManager);
//发送数据,将输入数据绑定到RecyclerView
EditText text = findViewById(R.id.message_text);
Button send_button = findViewById(R.id.sendmessage_button);
send_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String message=text.getText().toString();
data.add(message);
MessageAdaptger adaptger= new MessageAdaptger(data);
messagebox.setAdapter(adaptger);
}
});
}
}
实际微信分为自己发的,和接收到信息.自己发的在右侧,别人发的在左侧. 如何将发送的,接受的分别显示呢,只要重写适配器中的getItemViewType()方法即可. 前提是消息记录需要是对象,有type类型字段.用来区分是发还是收.
public void getItemViewType(int position ){
int item = data.get(position);
return item.type;
}
然后在onCreateViewHolder()方法中,viewType就是item.type参数.