文章目录

  • 控件
    • Button
    • TextView
    • EditText
    • ImageView
    • ProgressBar
    • AlertDialog
    • ProgressDialog
  • 布局
    • LenearLayout
      • android:layout_gravity
      • android:layout_weight
    • RelativeLayout
    • FrameLayout
    • 百分比布局
    • 其他
  • 自定义控件
  • ListView
    • 定制ListView UI
    • 优化
    • 点击事件
  • RecyclerView
    • 横向滚动和瀑布流
    • 点击事件
  • 实践 -- 对话框UI
  • OK,THANKS FOR READING.BYE BYE~

这次主要是控件。
出自《第一行代码(第二版)》,用于自己学(chao)习(shu)记录

控件

TextView、Button、EditText和ImageView这几个没啥好说的,比较简单。

Button

需要注意的是Button显示的英文都是默认大写的,需要设置属性android:textAllCaps=false就可以取消全部大写的设置了。

TextView

可以设置文字颜色、大小等,使用android:gravity属性设置文本的对齐方式。

EditText

通过android:hint设置默认显示的提示文字,点击文本框后消失。默认是文字如果超过一行的话会自动切换下一行,一直切换,如果设置android:maxLines属性,比如为2,则文本框最大就是两行,如果输入到第三行了,那么只会显示第2和3行,第一行就隐藏了。

ImageView

在属性中通过android:src="@drawble/xxx"设置图片资源,也可以在代码中通过imageview.setImageResource(R.drawble.xxx)进行设置。

ProgressBar

在xml中编写

<ProgressBarandroid:layout_width="match_parent"android:layout_height="wrap_content" />

即可设置一个进度条

但是在实际使用的时候进度条不是一直存在的,而是在我们需要的时候才会显示出来。
在Android中,所有控件都具有一个可见属性android:visiblity,可选值有三种visible、invisible和gone。默认为visible可见;invisible表示控件不可见,但是仍然保持原先的位置和大小,相当于透明了;gone表示不可见,也不占用任何屏幕空间。
也可以在代码中通过setVisibility()方法进行设置,参数值为View.INVISIBLE、View.INVISIBILITY和View.GONE。可以用getVisibility()方法获取控件的可见状态。
修改一下按钮的监听

Button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (MyProgressBar.getVisibility()==View.INVISIBLE)MyProgressBar.setVisibility(View.VISIBLE);elseMyProgressBar.setVisibility(View.INVISIBLE);}});

启动程序,按一次按钮可以显示进度条,再按一次就藏了


可以修改进度条的样式,比如改为水平进度条并设置最大值

<ProgressBarandroid:id="@+id/ProgressBar"android:layout_width="match_parent"android:layout_height="wrap_content"style="?android:attr/progressBarStyleHorizontal"android:max="100"/>

同时修改一下监听,按一下按钮进度增加一点

Button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {MyProgressBar.setProgress(MyProgressBar.getProgress()+10);}});


AlertDialog

最常使用到的对话库昂,用于提示警告,比如在退出时询问是否保存数据等,主要流程为new一个对象 -> 设置标题信息 -> 设置按钮和监听。其中setCancelable()方法是设置能否通过返回键关闭对话框。

Button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {AlertDialog.Builder alert=new AlertDialog.Builder(FirstActivity.this);alert.setTitle("This is a title");alert.setMessage("this is a message");alert.setCancelable(false);alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}});alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {}});alert.show();}});

ProgressDialog

这个对话框会显示一个进度条,一般用于让用户等待的时候,大体设置和AlertDialog差不多。
如果设置了setCancelable(false),表示无法使用返回键取消该对话框,需要在耗时事件结束后主动调用对话框的dismiss()方法销毁对话框。

布局

LenearLayout

线性布局可以通过android:orientation设置vertical还是horizontal。
要注意一下,如果设置vertical的话,高度就不能match_parent了,horizontal的话,宽度就不能match_parent了。

android:layout_gravity

指定布局中控件的对齐方式,如果是horizontal的话,只有垂直的对齐起作用,水平没用;如果是vertical的话,只有水平的对齐起作用,垂直没用。

android:layout_weight

按照比例指定控件的大小,在程序对不同手机的适配上起着很大的作用。如果有两个控件,android:layout_weight均为1,且布局为horizontal,则每个控件的宽度均为50%。
也可以制定部分控件的权重,如下

<?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"><Buttonandroid:id="@+id/Button_1"android:text="this is a button"android:layout_width="wrap_content"android:layout_height="wrap_content"/><EditTextandroid:layout_width="0dp"android:layout_height="wrap_content"android:hint="this is a textview"android:maxLines="2"android:layout_weight="1"/>
</LinearLayout>

RelativeLayout

通过相对定位的方式可以更加随意的确定控件的位置,这个布局方式有很多的属性可以设置,看个栗子吧

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/Button_1"android:text="this is a button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentBottom="true"/>
</RelativeLayout>

相对于父组件的位置的属性主要有android:layout_alignParentTop、android:layout_alignParentBottom、android:layout_alignParentRight、android:layout_alignParentTop和android:layout_centerInParent。

同时可以设置相对于控件的位置,属性比较多,有android_layout_above、android_layout_below、android_layout_toRightOf和android_layout_toLeftOf等,分别表示该控件位于上一个控件的上方、下方、右和左。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/Button_1"android:text="button 1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"/><Buttonandroid:id="@+id/Button_2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_above="@id/Button_1"android:layout_toRightOf="@id/Button_1"android:text="button 2"/><Buttonandroid:id="@+id/Button_3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/Button_1"android:layout_toLeftOf="@id/Button_1"android:text="button 3"/>
</RelativeLayout>

效果如下

除了相对位置,还有一组是相对对齐的属性,android:layout_alignRight、android:layout_alignLeft、android:layout_alignTop和android:layout_alignBottom,分别是将该控件和目标控件右对齐、左对齐,顶部对齐和底部对齐。

FrameLayout

帧布局相对简单,同样应用场所也比较少,所有控件默认放置左上角。
栗子

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/Button_1"android:text="button 1"android:layout_width="wrap_content"android:layout_height="wrap_content"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="This is a TextView"/>
</FrameLayout>

可以看到如果不设置的话,所有控件都默认在左上角放置。

可以通过android:layout_gravity在帧布局中对控件位置进行设置。

百分比布局

在LinearLayout中可以通过android:weight按比例修改控件大小,其余两种布局则不行,因此Android引入了百分比布局方式,不需要使用wrap_parent或者match_parent,可以直接设置百分比数值。
但是这是新增的,为了在所有版本上可以使用,Android团队把百分比布局定义在supprt库中了,只需要在build.gradle中添加库依赖就可以保证兼容性了。
compile ‘com.android.support:percent:24.2.1’
最好这个版本和appcompat的版本一致。

<?xml version="1.0" encoding="utf-8"?>
<android.support.percent.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:text="button 1"android:layout_gravity="left|top"app:layout_widthPercent="50%"app:layout_heightPercent="50%"/><Buttonandroid:text="button 2"android:layout_gravity="left|bottom"app:layout_widthPercent="50%"app:layout_heightPercent="50%"/><Buttonandroid:text="button 3"android:layout_gravity="right|top"app:layout_widthPercent="50%"app:layout_heightPercent="50%"/><Buttonandroid:text="button 4"android:layout_gravity="right|bottom"app:layout_widthPercent="50%"app:layout_heightPercent="50%"/>
</android.support.percent.PercentFrameLayout>

需要先写app命名空间,app:layout_widthPercent和app:layout_heightPercent,由于android.support.percent.PercentFrameLayout是继承FrameLayout布局,因此所有控件也是默认放置左上角的,避免重叠,可以通过android:layout_gravity设置放置的上下左右。

其他

除此之外的布局还包括AbsoluteLayout和TableLayout等等,只不过用的非常少。

自定义控件

按钮卓中也可以自定义控件,下图为一些控件之间的继承关系

所有控件都是直接或间接继承View,所有布局都是直接或间接继承ViewGroup。View是Android中最基本的UI组件,在屏幕上绘制一块矩形区域,并相应这个区域上的事件。所有控件都是在View的基础上添加各自的功能,ViewGroup是一种特殊的View,可以包含很多View和ViewGroup,是用于防止控件和布局的容器。
在此进行一个实例,自定义一个标题栏,需要使用的只有两个Button和一个TextView,如果多个活动中都需要使用该标题栏,如果每个活动都一个一个写一遍会很麻烦,因此如果可以写成一个控件直接引用就会方便很多。
主要是设置一下三个控件的android:layout_gravity,把TextView的宽度设为android:layout_weight=“1”,这里用到的三个背景图都是图片素材

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/title_bg"><Buttonandroid:text="back"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:background="@drawable/back_bg"/><TextViewandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:text="Title"android:textSize="24sp"android:layout_gravity="center"android:gravity="center"/><Buttonandroid:text="edit"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_margin="5dp"android:background="@drawable/edit_bg"/>
</LinearLayout>

在first_layout.xml中加一行,引入这个layout
<include layout="@layout/title"
之后在FirstActivity.java中去除原有的标题栏

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);ActionBar actionBar=getSupportActionBar();if (actionBar!=null)actionBar.hide();}

但是我的效果看起来好差啊

之后需要编写代码以响应控件中的事件,新建一个TitleLayout类,继承自LinearLayout,重写构造函数,表示在加载布局的时候会自动调用该构造方法,对标题栏自动加载。

public class TitleLayout extends LinearLayout {public TitleLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.title,this);}
}

布局文件中需要修改一下,把引入布局改成自定义控件

<com.example.k.androidpractice_1.TitleLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"/>

简单设置一下监听,注意这里的上下文获取,不是单纯的this

public TitleLayout(Context context, @Nullable AttributeSet attrs) {super(context, attrs);LayoutInflater.from(context).inflate(R.layout.title,this);//ListenButton BackButton=findViewById(R.id.BackButton);Button EditButton=findViewById(R.id.EditButton);BackButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {((Activity)getContext()).finish();}});EditButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(getContext(),"this is edit",Toast.LENGTH_SHORT).show();}});}

点击EDIT按钮可以看到有Toast弹出,说明事件响应成功。

ListView

是最常用的控件,可以通过滚动的方式显示屏幕以外的内容。
xml中添加一个简单控件代码就好了

<ListViewandroid:id="@+id/ListView_1"android:layout_width="match_parent"android:layout_height="match_parent"/>

ListView不能直接放置内容,需要通过适配器进行内容设置。利用从网上或者数据库中获得的数据,构造相应数组,建立适配器,给ListView传入适配器。其中android.R.layout.simple_list_item_1是安卓内置的一个layout的id,里面只有一个TextView。

private String[] data={"apple","banana","grape","beach","pea"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);ArrayAdapter<String> Adapter=new ArrayAdapter<String>(FirstActivity.this,android.R.layout.simple_list_item_1,data);ListView MyListView=findViewById(R.id.ListView_1);MyListView.setAdapter(Adapter);}

定制ListView UI

列表中不可能只有一个TextView,这里让他每一项显示一个TextView和ImageView。
先新建一个Fruit类,方便保存水果的信息,比如名字和图片ID等

public class Fruit {private String Name;private int ImageID;public Fruit(String Name,int ImageID){this.Name=Name;this.ImageID=ImageID;}public String getName(){return Name;}public int getImageID(){return ImageID;}
}

新建fruit_item.xml,编写列表每一项的布局
这里LinearLayout的width和height需要设置为wrap_content,不能用match_parent,否则将一个屏幕只有一种水果。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><ImageViewandroid:id="@+id/ImageView_1"android:layout_width="wrap_content"android:layout_height="wrap_content" /><TextViewandroid:id="@+id/TextView_1"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</LinearLayout>

编写自定义的适配器,新建FruitAdapter类,继承自ArrayAdapter,重写构造函数,传入上下文、ListViiew子项布局的id和数据。重写getView()方法,这个方法在每个子项滚动到屏幕内的时候被调用,这个方法中先得到这一项的Fruit实例,然后加载布局,之后设置图片和文字,返回布局view。

public class FruitAdapter extends ArrayAdapter {private int ID;public FruitAdapter(@NonNull Context context, int resource, List<Fruit> Object) {super(context, resource, Object);ID=resource;}public View getView(int position,View ConvertView,ViewGroup parent){Fruit fruit=(Fruit)getItem(position);View view= LayoutInflater.from(getContext()).inflate(ID,parent,false);ImageView FruitImage=(ImageView)view.findViewById(R.id.ImageView_1);TextView FruitName=(TextView)view.findViewById(R.id.TextView_1);FruitImage.setImageResource(fruit.getImageID());FruitName.setText(fruit.getName());return view;}
}

修改FirstActivity中的代码,先初始化,初始化的时候就是把所有水果的名字和图片放到List里面方便传参,for两遍是为了多弄点数据,new一个我们自定义的适配器,获取ListView,传入适配器参数。

public class FirstActivity extends AppCompatActivity {private List<Fruit>  FruitList=new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);initFruits();FruitAdapter Adapter=new FruitAdapter(FirstActivity.this,R.layout.fruit_item,FruitList);ListView MyListView=findViewById(R.id.ListView_1);MyListView.setAdapter(Adapter);}private void initFruits(){String[] ItemName={"apple","banana","orange","watermelon","pear","grape","pineapple","strawberry","cherry","mango"};int[] ItemImage={R.drawable.apple_pic,R.drawable.banana_pic,R.drawable.orange_pic,R.drawable.watermelon_pic,R.drawable.pear_pic,R.drawable.grape_pic,R.drawable.pineapple_pic,R.drawable.strawberry_pic,R.drawable.cherry_pic,R.drawable.mango_pic};for (int i=0;i<=1;i++){for (int j=0;j<ItemName.length;j++){Fruit Item=new Fruit(ItemName[j],ItemImage[j]);FruitList.add(Item);}}}
}

之后运行就可以看到有列表了

优化

上述的getView()方法在列表滚动的时候会全部重新加载,如果快速滚动的话效率会比较低,注意到getView()方法里面有一个参数是ConvertView,这个参数可以将之前加载的布局进行缓存,可以直接重用提高效率。

public View getView(int position,View ConvertView,ViewGroup parent){Fruit fruit=(Fruit)getItem(position);View view;if (ConvertView==null){view= LayoutInflater.from(getContext()).inflate(ID,parent,false);}elseview=ConvertView;ImageView FruitImage=(ImageView)view.findViewById(R.id.ImageView_1);TextView FruitName=(TextView)view.findViewById(R.id.TextView_1);FruitImage.setImageResource(fruit.getImageID());FruitName.setText(fruit.getName());return view;}

点击事件

通过OnItemClickListener监听单击事件。

RecyclerView

由于LIstView性能不是很好,而且只能用于垂直,不能水平滚动。
官方也更推荐RecyclerView。这个和百分比布局一样,也是新增的,需要添加依赖,同样最好版本相同
compile ‘com.android.support:recyclerview-v7:24.2.1’
修改一下布局的控件

<?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"><android.support.v7.widget.RecyclerViewandroid:id="@+id/RecyclerView_1"android:layout_width="match_parent"android:layout_height="match_parent"/>
</LinearLayout>

这里需要一个新的适配器,继承自RecyclerView.Adapter。先定义了一个内部类ViewHolder,方便处理两个控件实例,构造函数中传入View参数,通常是子项的最外层布局,可以从中获得TextView和ImageView。主类FruitAdapter的构造函数的参数是传入List数据。
继承之后需要重写三个方法,onCreateViewHolder()方法创建ViewHolder实例,将其中的Fruit对象放到布局里面加载出来,返回实例。
onBindViewHolder()方法可以给每个子项的数据赋值,在子项滚到屏幕内时执行,通过positon获得子项实例,然后设置数据到ViewHolder里面。
getItemCount()就是子项长度。

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> FruitList;static class ViewHolder extends RecyclerView.ViewHolder {ImageView MyImageView;TextView MyTextView;public ViewHolder(View view) {super(view);MyImageView = (ImageView) view.findViewById(R.id.ImageView_1);MyTextView = (TextView) view.findViewById(R.id.TextView_1);}}@Overridepublic 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;}@Overridepublic void onBindViewHolder(FruitAdapter.ViewHolder holder, int position) {Fruit fruit=FruitList.get(position);holder.MyImageView.setImageResource(fruit.getImageID());holder.MyTextView.setText(fruit.getName());}@Overridepublic int getItemCount() {return FruitList.size();}public FruitAdapter(List<Fruit> FruitList){this.FruitList=FruitList;}
}

修改FirstActivity

public class FirstActivity extends AppCompatActivity {private List<Fruit>  FruitList=new ArrayList<>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);initFruits();RecyclerView MyRecyclerView=(RecyclerView)findViewById(R.id.RecyclerView_1);LinearLayoutManager LayoutManager=new LinearLayoutManager(this);MyRecyclerView.setLayoutManager(LayoutManager);FruitAdapter Adapter=new FruitAdapter(FruitList);MyRecyclerView.setAdapter(Adapter);}private void initFruits(){String[] ItemName={"apple","banana","orange","watermelon","pear","grape","pineapple","strawberry","cherry","mango"};int[] ItemImage={R.drawable.apple_pic,R.drawable.banana_pic,R.drawable.orange_pic,R.drawable.watermelon_pic,R.drawable.pear_pic,R.drawable.grape_pic,R.drawable.pineapple_pic,R.drawable.strawberry_pic,R.drawable.cherry_pic,R.drawable.mango_pic};for (int i=0;i<=1;i++){for (int j=0;j<ItemName.length;j++){Fruit Item=new Fruit(ItemName[j],ItemImage[j]);FruitList.add(Item);}}}
}

之后就成功了,只不过这个大小有点奇怪,原因应该是我的fruit_item.xml没写好,不管了
得管,问题大概是fruit_item里面的设置问题,LinearLayout需要将width设为wrap_parent,height设为wrap_content,控件属性都是wrap_content

横向滚动和瀑布流

实现横向滚动首先先将fruit_item.xml的布局改一下,需要上面是图片下面是名字,这样才好水平放置。
宽度设为100dp,若为match则可能会过度拉伸,wrap会有长有短不好看,因此固定长度。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="100dp"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/ImageView_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"/><TextViewandroid:id="@+id/TextView_1"android:layout_width="wrap_content"android:layout_gravity="center_horizontal"android:layout_marginTop="10dp"android:layout_height="wrap_content"/>
</LinearLayout>

之后修改FirstActivity.java代码的onCreate()方法,就只需要加一句即可LayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);initFruits();RecyclerView MyRecyclerView=(RecyclerView)findViewById(R.id.RecyclerView_1);LinearLayoutManager LayoutManager=new LinearLayoutManager(this);LayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);MyRecyclerView.setLayoutManager(LayoutManager);FruitAdapter Adapter=new FruitAdapter(FruitList);MyRecyclerView.setAdapter(Adapter);}

可以看到已经横向展示了

除了LinearLayoutManager,RecyclerView还提供了另外两种布局方式,分别是GridLayoutManager和StaggeredGridLayoutManager,后者可以实现瀑布流。
修改fruit_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="5dp"><ImageViewandroid:id="@+id/ImageView_1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"/><TextViewandroid:id="@+id/TextView_1"android:layout_width="wrap_content"android:layout_gravity="left"android:layout_marginTop="10dp"android:layout_height="wrap_content"/>
</LinearLayout>

修改FirstActivity.java的onCreate(),再添加一个随机生成文件名的函数,长度不定用来展示这个布局管理,当各个子项不一样高的时候更能体现瀑布流的特点。StaggeredGridLayoutManager的两个参数第一个表示三列,第二个表示垂直方向。

protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);initFruits();RecyclerView MyRecyclerView=(RecyclerView)findViewById(R.id.RecyclerView_1);StaggeredGridLayoutManager LayoutManager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);MyRecyclerView.setLayoutManager(LayoutManager);FruitAdapter Adapter=new FruitAdapter(FruitList);MyRecyclerView.setAdapter(Adapter);}
...
private String getRandomLengthName(String Name){Random random=new Random();int length=random.nextInt(20)+1;StringBuilder sb=new StringBuilder();for (int i=0;i<length;i++){sb.append(Name);}return sb.toString();}

然后运行

点击事件

RecyclerView的点击和ListView的点击实现不一样,没有现成的监听器方法之类的,需要对每一个view进行点击事件的注册,为什么要这么麻烦呢?如果子项中有按钮,我们只需要点击按钮的时候,ListView不能很好的满足这个需求,因此RecyclerView干脆删除了这个监听器。
修改FruitAdapter代码,在FruitAdapter类中添加一个View类型变量FruitView,在ViewHolder()构造方法中给FruitView赋值view,在ViewHolder()中进行监听注册

...
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {private List<Fruit> FruitList;static class ViewHolder extends RecyclerView.ViewHolder {ImageView MyImageView;TextView MyTextView;View FruitView;public ViewHolder(View view) {super(view);FruitView=view;MyImageView = (ImageView) view.findViewById(R.id.ImageView_1);MyTextView = (TextView) view.findViewById(R.id.TextView_1);}}@Overridepublic 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() {@Overridepublic void onClick(View v) {int position=holder.getAdapterPosition();Fruit fruit=FruitList.get(position);Toast.makeText(v.getContext(),fruit.getName(),Toast.LENGTH_SHORT).show();}});holder.MyImageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {int position=holder.getAdapterPosition();Fruit fruit=FruitList.get(position);Toast.makeText(v.getContext(),fruit.getName(),Toast.LENGTH_SHORT).show();}});return holder;}
...}

可以看到,此时不仅是点击图片还是名字都会有Toast弹出,说明成功。

实践 – 对话框UI

首先需要知道如何制作Nine-Patch图片,是一种被特殊处理过的PNG图片,能够指定某些区域被拉伸,某些区域不被拉伸。
比如有这个图片

如果被拉伸了可能会是这个样子

而安卓中有一个工具是专门制作这种图片的,在Android SDK/tools/draw9patch.bat,在使用的时候需要将Android SDK/jre/bin添加到环境变量中,双击打开

然后把图片复制到drawable文件夹中,给LinearLayout设置background,不用添加控件,width设为match_parent,height为wrap_content,效果如下

开始写主界面

filename:first_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#d8d0d8"><android.support.v7.widget.RecyclerViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><EditTextandroid:id="@+id/InputMessage"android:layout_width="0dp"android:layout_height="wrap_content"android:hint="Input your message"android:maxLines="2"android:layout_weight="1"/><Buttonandroid:id="@+id/Send"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Send"/></LinearLayout>
</LinearLayout>

定义消息的实体类Msg,其中Type变量用于标记该消息是接收的还是发送的。

filename:Msg.java
package com.example.k.androidpractice_1;/*** Created by kang on 2020/1/30.*/public class Msg {public static final int TYPE_RECEIVED=0;public static final int TYPE_SEND=1;private String Content;private int Type;public Msg(String Content,int Type){this.Content=Content;this.Type=Type;}public String getContent(){return Content;}public int getType(){return Type;}
}

编写RecyclerView的子项布局msg_items.xml,这里有两个Layout,分别是接收消息和发送消息的对话框,在代码中通过可见属性决定显示什么。

filename:mas_items.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayoutandroid:id="@+id/Left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/message_left"android:layout_gravity="left"><TextViewandroid:id="@+id/LeftMessage"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#fff"android:layout_gravity="center"/></LinearLayout><LinearLayoutandroid:id="@+id/Right"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/message_right"android:layout_gravity="right"><TextViewandroid:id="@+id/RightMessage"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#fff"android:layout_gravity="center"/></LinearLayout>
</LinearLayout>

又到了适配器,现在适配器有点上手了,在绑定数据的时候先判断是接收的还是发送的,设置对应的可见属性。

package com.example.k.androidpractice_1;import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;import java.util.ArrayList;
import java.util.List;/*** Created by kang on 2020/1/30.*/public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {private List<Msg> MyMessageList=new ArrayList<>();@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_items,parent,false);return new ViewHolder(view);}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {Msg Message=MyMessageList.get(position);if (Message.getType()==Msg.TYPE_RECEIVED){holder.LeftLayout.setVisibility(View.VISIBLE);holder.RightLayout.setVisibility(View.GONE);holder.LeftMessageTextView.setText(Message.getContent());}else{holder.LeftLayout.setVisibility(View.GONE);holder.RightLayout.setVisibility(View.VISIBLE);holder.RightMessageTextView.setText(Message.getContent());}}@Overridepublic int getItemCount() {return MyMessageList.size();}static class ViewHolder extends RecyclerView.ViewHolder{LinearLayout LeftLayout,RightLayout;TextView LeftMessageTextView,RightMessageTextView;public ViewHolder(View view){super(view);LeftLayout=view.findViewById(R.id.Left);RightLayout=view.findViewById(R.id.Right);LeftMessageTextView=view.findViewById(R.id.LeftMessage);RightMessageTextView=view.findViewById(R.id.RightMessage);}}public MsgAdapter(List<Msg> MessageList){MyMessageList=MessageList;}
}

然后在FirstActivity.java进行初始化,设置数据,主要就还是获取控件实例,设置适配器和监听,数据初始化。在发送消息后,调用MessageAdapter.ntifyItemChanged()方法,在有消息的时候进行刷新。调用MessageRecyclerView.scrollToPosition()方法将列表滚动到最后一项。

filename:FirstActivity.java
package com.example.k.androidpractice_1;import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class FirstActivity extends AppCompatActivity {private List<Msg> MessageList=new ArrayList<>();private EditText InputMessageEditText;private Button SendButton;private RecyclerView MessageRecyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.first_layout);initMsgs();InputMessageEditText=findViewById(R.id.InputMessage);SendButton=findViewById(R.id.Send);MessageRecyclerView=findViewById(R.id.MessageList);LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);MessageRecyclerView.setLayoutManager(linearLayoutManager);final MsgAdapter MessageAdapter=new MsgAdapter(MessageList);MessageRecyclerView.setAdapter(MessageAdapter);SendButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String Content=InputMessageEditText.getText().toString();if (!"".equals(Content)){Msg Message=new Msg(Content,Msg.TYPE_SEND);MessageList.add(Message);               //添加消息//MessageAdapter.notifyItemChanged(MessageList.size()-1);     //有消息的时候,刷新MessageRecyclerView.scrollToPosition(MessageList.size()-1);     //滚动到最后一项InputMessageEditText.setText("");}}});}private void initMsgs(){Msg Message1=new Msg("this is a message 1",Msg.TYPE_SEND);MessageList.add(Message1);Msg Message2=new Msg("this is a message 22222",Msg.TYPE_RECEIVED);MessageList.add(Message2);}
}

随后运行程序可以看到已经成功了


但是有一个问题,监听里面的MessageAdapter.notifyItemChanged(MessageList.size()-1);这一行如果不注释掉会报错,而且报错内容似乎是控件自身

<font color="red">
E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.example.k.androidpractice_1, PID: 20929java.lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v4/animation/AnimatorCompatHelper;at android.support.v7.widget.DefaultItemAnimator.resetAnimation(DefaultItemAnimator.java:515)at android.support.v7.widget.DefaultItemAnimator.animateAdd(DefaultItemAnimator.java:218)at android.support.v7.widget.SimpleItemAnimator.animateAppearance(SimpleItemAnimator.java:114)at android.support.v7.widget.RecyclerView.animateAppearance(RecyclerView.java:3528)at android.support.v7.widget.RecyclerView$4.processAppeared(RecyclerView.java:461)at android.support.v7.widget.ViewInfoStore.process(ViewInfoStore.java:249)at android.support.v7.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:3385)at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3135)at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3568)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)at android.widget.FrameLayout.onLayout(FrameLayout.java:261)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.support.v7.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:443)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)at android.widget.FrameLayout.onLayout(FrameLayout.java:261)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1812)at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1656)at android.widget.LinearLayout.onLayout(LinearLayout.java:1565)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)at android.widget.FrameLayout.onLayout(FrameLayout.java:261)at com.android.internal.policy.DecorView.onLayout(DecorView.java:753)at android.view.View.layout(View.java:20672)at android.view.ViewGroup.layout(ViewGroup.java:6194)at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2792)at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2319)at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1460)at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)at android.view.Choreographer$CallbackRecord.run(Choreographer.java:949)at android.view.Choreographer.doCallbacks(Choreographer.java:761)at android.view.Choreographer.doFrame(Choreographer.java:696)at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:935)at android.os.Handler.handleCallback(Handler.java:873)at android.os.Handler.dispatchMessage(Handler.java:99)at android.os.Looper.loop(Looper.java:193)at android.app.ActivityThread.main(ActivityThread.java:6669)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
E/AndroidRuntime: Caused by: java.lang.ClassNotFoundException: Didn't find class "android.support.v4.animation.AnimatorCompatHelper" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.example.k.androidpractice_1-qLD9Df1Lh_NOfCKU_GrQ2w==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.k.androidpractice_1-qLD9Df1Lh_NOfCKU_GrQ2w==/lib/x86, /system/lib]]at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)at java.lang.ClassLoader.loadClass(ClassLoader.java:379)at java.lang.ClassLoader.loadClass(ClassLoader.java:312)... 52 more
</font>
I/Process: Sending signal. PID: 20929 SIG: 9
Application terminated.

这个问题我还没查是为什么,暂时就先不要这一行了。
Over

OK,THANKS FOR READING.BYE BYE~

Android开发 入门篇(二) - 常用UI控件相关推荐

  1. 安卓入门系列-07常用UI控件(长文)

    常用UI控件 简介 这一篇介绍开发中的常用UI控件. 布局管理器 所有布局管理器都是ViewGroup的子类,都可作为容器类使用.继承自View,所以也可嵌套. 常见的布局之前已经提到了三种,这里不再 ...

  2. IOS 常用UI控件

    目录 下拉刷新 模糊效果 AutoLayout 富文本 图表 表相关与Tabbar 隐藏与显示 HUD与Toast 对话框 其他UI 具体内容 下拉刷新 EGOTableViewPullRefresh ...

  3. android button imagebutton 区别,Android 开发入门篇

    Button 与 ImageButton 本节学习Android基本控件按钮控件,Button和ImageButton用法基本类似,所以本节重点讲解Button控件. 在布局中添加Button控件: ...

  4. ios 设置属性的center_IOS开发-常用UI控件的基本使用(Transform形变属性、frame属性、center属性的使用)...

    3. disabled(失效状态,不可用状态) 如果enabled属性为NO,就是处于disable状态,代表按钮不可以被点击,默认情况是可以点击的. 对应的枚举常量:UIControlStateDi ...

  5. 野人学Android基础篇之初探UI控件第一课--TextView动态赋值

    除了上节课中讲到的TextView静态赋值,还有一种更加灵活的赋值方法–动态赋值.在app的运行过程中,根据程序的需要可以随时改变TextView的值. 其实现的基本逻辑可以归纳如下: 1.通过id获 ...

  6. FreeCAD二次开发:集成二维CAD控件MxDraw

    济南友泉软件有限公司 FreeCAD是一套基于OpenCASCADE/QT的三维全参数化建模开源代码,虽然提供了Draft.TechDraw等二维绘图功能,但是其二维建模能力仍旧比较弱. Ref. f ...

  7. ArcGIS for Android Runtime100 基本操作(二)——地图控件的常见操作

    以前我刚开始学习ArcGIS时候,看得最常见的一篇博客是Ersi中国官方写的一篇<ArcGIS for Android地图控件的5大常见操作>,地址是http://blog.csdn.ne ...

  8. Android自定义控件入门实践之雷达扫描控件

    以前因为工作的关系,对于自定义控件用的少之又少,无非就是把几个控件放置到ViewGroup内部,然后提供开放方法,就成了一个所谓的自定义控件,但是这种小伎俩太简单,面试的时候这点东西根本Hold不住场 ...

  9. 一些常用UI控件汇总

    1.标签控件 UIlable 作用:显示文本 常用属性: (1).lineBreakMode //label宽度不够时,对文本的打断方式,默认为打断文本尾部 (2).shadowColor //设置l ...

最新文章

  1. 进阶必备:CNN经典论文代码复现 | 附下载链接
  2. [置顶]       设计模式之创建类模式——原型模式
  3. 机房管理系列之文件服务器管理
  4. 课堂上的社死现场...
  5. 人脸识别屡遭非议,会成为“潘多拉魔盒”吗?
  6. 使用脚本创建查找修改销毁游戏对象
  7. 可长点心吧-sort
  8. 2.word转换为pdf
  9. linux下解压 编译 安装,Linux 下开发环境安装配置-编译、解压、超链、
  10. 系统学习机器学习之正则化(一)
  11. 如何将response里header的date转化为当地时间_将产品20元利润提升到2000元,靠的是卖体验!...
  12. matlab建模和仿真实验,MATLAB-Simulink系统建模与仿真-实验报告
  13. C#使用oledb连接excel执行Insert Into语句出现“操作必须使用一个可更新的查询”的解决办法
  14. 乡镇政府网络智能办公系统(乡镇OA)应用【乡镇信息化经验】
  15. 如何获取QQ邮箱授权码
  16. 工程经济学99分速成复习——第一章 绪论
  17. 【Java书笔记】:《Redis 深度历险:核心原理和应用实践》分布式锁,延时队列,位图,HyperLogLog,布隆过滤器,漏斗限流,GeoHash,Scan,管道,事务,主从,Redis源码
  18. matlab程序是什么格式,科学网—Matlab中的P代码文件 - 杨笔锋的博文
  19. ECSHOP V2.7.3文件目录结构
  20. 我发现一个地方能免费领取价值198元的手环,具有能量并且有高人加持过的,只要关注微信就可以免费领取

热门文章

  1. js中的上下文,好比煮一顿泡面
  2. CodeForces - 108A Palindromic Times
  3. win10应用商店linux_Windows 10 在安装Ubuntu(WSL)后UWP与应用商店全面闪退//The UWP - Microsoft Community...
  4. 《The Witness》:游戏中的建筑学(上)
  5. 【转】ASCII码十进制、十六进制对照表
  6. 环回接口(Loopback Interface)【转】
  7. busybox ync.c:(.text.sync_main+0x78): undefined reference to `syncfs' 出错
  8. Android自学之路,DrawerLayout must be measured with MeasureSpec.EXACTLY.错误
  9. [NOI2016]旷野大计算
  10. 皇帝内经:恬淡虚无,真气从之,精神内守,病安从来?