文章目录
- **`TestView`**
- **`Toast`**
- **`CheckBox`**
- **`RadioGroup&RadioButton`**
- **`Button`**
- **`EditText`**
- **`ImageView`**
- **`进度条`**
- **`ProgressBar`**
- **`SeekBar`**
- **`RatingBar`**
- **`AlertDialog`**
- **`ProgressDialog`**
- **`时间日期控件`**
- **`TimePicker`**
- **`DatePicker`**
- **`ListView`**
- **`RecyclerView`**
- **`WebView`**
- ScrollView—让你的布局滚动起来
TestView
它主要用于在界面上显示一段文本信息
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="24sp"
android:textColor="#00ff00"
android:text="This is TextView"/>
android:id
给当前控件定义一个唯一标识符
android:layout_width
和 android:layout_height
指定控件的宽度和高度。Android所有的空间都有这两个属性,可选值三种,match_parent
表示让当前控件的大小和父布局大小一样。也就是由父布局决定控件的大小fill_parent
和 match_parent相似wrap_content
表示让当前空间的大小能够刚好包含住里面的内容。也就是与控件的内容决定控件的大小
android:text
指定TextView中显示的文本
android:gravity
来指定文字的对齐方式,可选值有top,bottom,left,right,center等,可以用 |
来同时指定多个值,这里我们指定的center,效果等同于center_vertical|
center_horizontal,表示文字在垂直和水平方向都居中对齐。
android:textSize
属性可以指定文字的大小
android:textColor
属性可以指定文字的颜色
Toast
Toast
是Android 系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息通知给用户,这些信息在一段时间后会自动消失,并且不会占用任何屏幕空间。
该方法的一般用法:
Toast toast = Toast.makeText(context, “”, time);
这三个参数分别是:
1.当前的上下文环境;(getApplicationContext这个方法可以获取)
2.要显示的字符串;(就是一般的字符串,可以写在string.xml中)
3.显示的时间长短;(有toast默认的参数,也可以自己设定)
Toast.makeText(FirstActivity.this,"i learn english",
Toast.LENGTH_SHORT).show();
CheckBox
多选框,一个CheckBox对应一个框。
注册点击事件
监听器
public class MainActivity extends AppCompatActivity {
private CheckBox eatBox;
private CheckBox sleepBox;
private CheckBox playBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
eatBox = (CheckBox) findViewById(R.id.eatBox);
sleepBox = (CheckBox) findViewById(R.id.sleepBox);
playBox = (CheckBox) findViewById(R.id.playBox);
OnBoxClickListener listener = new OnBoxClickListener();
eatBox.setOnClickListener(listener);
sleepBox.setOnClickListener(listener);
playBox.setOnClickListener(listener);
}
class OnBoxClickListener implements View.OnClickListener{
@Override
public void onClick(View view) {
CheckBox box = (CheckBox) view;
String Msg = "";
if(box.getId() == R.id.eatBox) Msg = "eatBox";
else if(box.getId() == R.id.sleepBox) Msg = "sleepBox";
else if(box.getId() == R.id.playBox) Msg = "playBox";
if(box.isChecked()) Msg += " checked!";
else Msg += " unchecked!";
Toast.makeText(MainActivity.this,Msg,Toast.LENGTH_SHORT).show();
}
}
}
注册状态改变事件
监听器
public class MainActivity extends AppCompatActivity {
private CheckBox eatBox;
private CheckBox sleepBox;
private CheckBox playBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
eatBox = (CheckBox) findViewById(R.id.eatBox);
sleepBox = (CheckBox) findViewById(R.id.sleepBox);
playBox = (CheckBox) findViewById(R.id.playBox);
CheckBoxListener listener = new CheckBoxListener();
eatBox.setOnCheckedChangeListener(listener);
sleepBox.setOnCheckedChangeListener(listener);
playBox.setOnCheckedChangeListener(listener);
}
class CheckBoxListener implements CompoundButton.OnCheckedChangeListener {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
String Msg = "";
if(compoundButton.getId() == R.id.playBox)
if(b) Msg = "playBox checked!";
else Msg = "PlayBox unchecked!";
else if(compoundButton.getId() == R.id.sleepBox)
if(b) Msg = "sleepBox checked!";
else Msg = "sleepBox unchecked!";
else if(compoundButton.getId() == R.id.eatBox)
if(b) Msg = "eatBox checked!";
else Msg = "eatBox unchecked!";
Toast.makeText(MainActivity.this,Msg,Toast.LENGTH_SHORT).show();
}
}
}
isChecked()
判断当前框是否被选中setCheckted(boolean)
设置当前框的状态
RadioGroup&RadioButton
单选按钮在逻辑上是成组出现的,即一组中只能选择一个按钮。
RadioButton 是 RadioGroup的字标签,xml文档中如下表示
<RadioGroup
android:id="@+id/group1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="男性"/>
<RadioButton
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="女性"/>
</RadioGroup>
注册OnCheckedChangeListene
r监听器的方式有两种,一个是为每一个按钮注册监听器,一个是为每一组注册一个监听器。
注意:两个监听器虽然名字都是·OnCheckedChangeListener·,但在不同包下,为按钮注册的监听器和多选按钮注册的包名一样 ,是CompoundButton;而为组对象注册的监听器包是RadioGroup。
下面是选择为组对象注册监听器
public class MainActivity extends AppCompatActivity {
private RadioGroup radioGroup;
private RadioButton radioButton1;
private RadioButton radioButton2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
radioGroup = (RadioGroup) findViewById(R.id.group1);
radioButton1 = (RadioButton) findViewById(R.id.button1);
radioButton2 = (RadioButton) findViewById(R.id.button2);
RadioGroupListener listener = new RadioGroupListener();
radioGroup.setOnCheckedChangeListener(listener);
}
class RadioGroupListener implements RadioGroup.OnCheckedChangeListener{
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
String Msg = "";
if(i == radioButton1.getId()) Msg = "male checked!";
else if(i == radioButton2.getId()) Msg = "female checked!";
Toast.makeText(MainActivity.this, Msg, Toast.LENGTH_SHORT).show();
}
}
}
Button
注意系统会默认将Button的所有英文字符自动进行大写转换,我们要通过android:textAllCaps
属性来禁用它。
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="Button"/>
然后我们在活动类中为Button的点击事件注册一个监听器匿名类的方式来注册监听器
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
//再此处添加逻辑
}
});
}
}
如果不喜欢这种匿名类的方式来注册监听器,也可以使用实现接口
的方式来进行注册。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
//在此处添加逻辑
break;
default:
break;
}
}
}
内部类实现注册监听器
public class MainActivity extends AppCompatActivity {
private CheckBox eatBox;
private CheckBox sleepBox;
private CheckBox playBox;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
eatBox = (CheckBox) findViewById(R.id.eatBox);
sleepBox = (CheckBox) findViewById(R.id.sleepBox);
playBox = (CheckBox) findViewById(R.id.playBox);
OnBoxClickListener listener = new OnBoxClickListener();
eatBox.setOnClickListener(listener);
sleepBox.setOnClickListener(listener);
playBox.setOnClickListener(listener);
}
class OnBoxClickListener implements View.OnClickListener{
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"hello",Toast.LENGTH_SHORT).show();
}
}
EditText
android:hint
属性让我们可以添加提示文字
android:maxLines
指定EditText的最大行数。当输入的文字超过指定的行数时,文本就会向上滚动,而EditText则不会在继续延伸
实例:Button 与 EditText结合
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
String inputText = editText.getText().toString();
Toast.makeText(MainActivity.this,inputText,
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
ImageView
ImageView是用于在界面上展示图片的一个控件,它可以让我们的程序世界变得更加丰富多彩。
图片通常都是放在以’drawable’开头的目录下的,并且指定分辨率。
android:src
属性给Image_View指定一张图片。android:scaleType
属性 不匹配情况下拉伸图片
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_1"/>
按钮事件来显示指定的图片
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
imageView = (ImageView) findViewById(R.id.image_view);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
imageView.setImageResource(R.drawable.img_2);
break;
default:
break;
}
}
}
进度条
ProgressBar
ProgressBar 用于在界面上显示一个进度条,表示我们的程序正在加载一些数据。
<ProgressBar
android:id="@+id/progesss_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"/>
style
属性设置ProgressBar样式
android:max
属性给进度条设置一个最大值android:progress 属性
设置进度条当前进度值
怎么让进度条消失,所以android 控件都有这个属性,android:visibility
,可选值有三种visible
表示控件是课件的,默认值invisible
表示控件不可见,但是仍然占据空间gone
表示控件不可见,也不占据空间
我们还可以通过代码设置控件的可见性,使用的是setVisibility()
方法,可以传入View.VISIBLE
,View.INVISIBLE
和View.GONE
这3种值。
通过点击按钮来增加进度值。
package com.example.uiwidgettest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
progressBar = (ProgressBar) findViewById(R.id.progesss_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
int progress = progressBar.getProgress();
progress = progress + 10;
progressBar.setProgress(progress);
break;
default:
break;
}
}
}
SeekBar
可拖动的进度条。
public class MainActivity extends AppCompatActivity {
private SeekBar seekBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
seekBar = (SeekBar) findViewById(R.id.s1);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
/**
*
* @param seekBar 触发了监听器的SeekBar对象
* @param progress 当前SeekBar对象的进度
* @param fromuser 是不是用户拖动导致进度条发生改变
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromuser) {
Toast.makeText(MainActivity.this,progress +" " +fromuser,
Toast.LENGTH_SHORT).show();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
Toast.makeText(MainActivity.this,"Star",
Toast.LENGTH_SHORT).show();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
Toast.makeText(MainActivity.this,"End",
Toast.LENGTH_SHORT).show();
}
});
}
}
RatingBar
public class MainActivity extends AppCompatActivity {
private RatingBar ratingBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ratingBar = (RatingBar) findViewById(R.id.r1);
ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
@Override
public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUsre) {
Log.d("My","rating: " + rating +" fromUser: " + fromUsre);
}
});
}
}
AlertDialog
AlertDialog 可以在当前的界面弹出一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽其他控件的交互能力,因此AlertDialog 一般都是用于提示一些非常重要的内容或者警告信息。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
progressBar = (ProgressBar) findViewById(R.id.progesss_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
AlertDialog.Builder dialog= new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is Dialog");
dialog.setMessage("Something important.");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//设置确定按钮的点击
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
//设置取消按钮的点击事件
}
});
AlertDialog dialog_entry = dialog.create();
dialog_entry.show();//显示对话框
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.parseColor("#fd8d99"));//给按钮换颜色
break;
default:
break;
}
}
}
首先通过AlertDialog.Builder创建一个AlertDialog的实例,然后可以为这个对话框设置标题、内容,可否取消等属性,接下来调用setPositiveButton()方法为对话框确定按钮的点击事件,调用setNegativeButton()方法设置取消按钮的点击事件,最后调用show()方法将对话框显示出来。
ProgressDialog
和 AlertDialog比较类似,不同的是,ProgressDialog会在对话框中显示一个进度条,一般用于表示当前操作比较耗时,让用户耐心等待。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
editText = (EditText) findViewById(R.id.edit_text);
progressBar = (ProgressBar) findViewById(R.id.progesss_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch(view.getId()){
case R.id.button:
ProgressDialog progressdialog= new ProgressDialog (MainActivity.this);
progressdialog.setTitle("This is ProgressDialog");
progressdialog.setMessage("Loading...");
progressdialog.setCancelable(true);
progressdialog.show();//显示对话框
break;
default:
break;
}
}
}
注意,如果在setCancelable()中传入了false,表示ProgressDialog是不能通过Back键取消掉的,这是你就一定要在代码中做好控制,当数据加载完成后必须要调用ProgressDialog的dismiss()方法来关闭对话框,否则ProgressDialog将会一直存在
时间日期控件
TimePicker
时间控件
注册OnTimeChangedListener监听器(匿名类方式
)
public class MainActivity extends AppCompatActivity {
private TimePicker timePicker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timePicker = (TimePicker) findViewById(R.id.p1);
timePicker.setIs24HourView(true);
timePicker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker timePicker, int i, int i1) {
Toast.makeText(MainActivity.this,"Hour: "+i + " Minute: " + i1,
Toast.LENGTH_SHORT).show();
}
});
}
}
DatePicker
日期控件
ListView
当我们的程序有大量的数据需要展示的时候,就可以借助ListView来实现,它允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚出屏幕。
常用属性
分割线属性divider
Item按下颜色listSelector
右侧快速滑动标签fastScroll
去除ListView滑到顶部和底部时边缘的黑色阴影
按下阴影显示Item之上drawSelectorOnTop
具体请访问链接
一个简单的用法
activity_main.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">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private String[] data = {"Apple","Banana","Orage","Watermelon",
"Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
"Apple","Banana","Orage","Watermelon","Pear","Grape","Pineapple",
"Strawberry","Cherry","Mango"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("水果篮");
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);
}
}
这里我们简单用一个data数组测试,里面包含很多水果名称
不过,数组中的数据是无法直接传递给ListView的,我们还需要借助适配器来完成。Android中提供很多适配器的实现类,其中我认为最好用的就是ArrayAdapter,他可以借助泛型来指定要是适配的数据类型,然后在构造函数中把要适配的数据传入。
ArrayAdapter 有多个构造函数的重载,你应该根据实际情况选择最合适的一种。
定制ListView的界面
效果如下
我们定义一个实体类Fruit类,作为ListView适配器的适配类型。
public class Fruit {
private String name;//水果名称
private int imageId;//水果图片
private String text;//水果描述
public Fruit(String name,int imageId,String text){
this.name = name;
this.imageId = imageId;
this.text = text;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
public String getText(){
return text;
}
}
然后为ListView的子项指定一个自定义的布局fruit_item.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">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
/>
<TextView
android:id="@+id/fruitText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="bottom"
android:layout_marginTop="10dp"/>
</LinearLayout>
</LinearLayout>
然后创建一个自定义的适配器类FruitAdapter,这个适配器继承自ArrayAdapter,并 将泛型指定为Fruit.
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
public FruitAdapter(@NonNull Context context, int resource,
@NonNull List<Fruit> objects) {
super(context, resource, objects);
resourceId = resource;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit = getItem(position);//获取当前Fruit实例
View view;
ViewHolder viewHolder;
if(convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
viewHolder.fruitText = (TextView) view.findViewById(R.id.fruitText);
view.setTag(viewHolder);//将ViewHolder存储在View中
}
else{
view = convertView;
viewHolder = (ViewHolder) view.getTag();//重新获取ViewHolder
}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
viewHolder.fruitText.setText(fruit.getText());
return view;
}
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
TextView fruitText;
}
}
FruitAdapter重写了父类的一组构造方法,用于将上下文,ListView子项布局的id和数据都传进来。然后重写了getView方法,这个方法在每个子项被滚动到屏幕内的时候会被调用。
getView()方法中有个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便重用,这样就不会每次都重新加载布局了。然后我们新建类ViewHolder用来解决每次都调用findViewById()来获取控件实例的问题。
接下来我们修改MainActivity.java代码
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();//初始化水果数据
FruitAdapter adapter = new FruitAdapter(MainActivity.this,
R.layout.fruit_item,fruitList);
ListView listView = (ListView) findViewById(R.id.lv1);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new ListView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Fruit fruit = fruitList.get(i);
Toast.makeText(MainActivity.this,fruit.getName(),
Toast.LENGTH_SHORT).show();
}
});
}
private void initFruits() {
for(int i = 0;i < 2;++ i){
Fruit apple = new Fruit("Apple",R.drawable.apple_pic,"This is an apple.");
fruitList.add(apple);
Fruit banana = new Fruit("Banana",R.drawable.banana_pic,"This is a banana.");
fruitList.add(banana);
Fruit orange = new Fruit("Orange",R.drawable.orange_pic,"This is an orange.");
fruitList.add(orange);
Fruit pear = new Fruit("Pear",R.drawable.pear_pic,"This is a pear.");
fruitList.add(pear);
}
}
}
我们在onCreate()方法中创建FruitAdapter对象,并将FruitAdapter作为适配器传给ListView。这样页面就完成了。
最后我们使用setOnItemClickListener()方法为ListView注册一个监听器,当用户点击ListView中的任何一个子项时,就会回调onItemClick()方法。
RecyclerView
更强大的滚动控件,可以说是增强版的ListView,不仅可以轻松实现和ListView同样的效果,还优化了ListView中存在的各种不足。
因为RecyclerView属于新增的控件,Android将RecyclerView定义在support库里。若要使用RecyclerView,第一步是要在build.gradle中添加对应的依赖库。
添加RecyclerView 依赖库app/build.gradle
中的dependencies闭包
添加以下内容:
implementation 'com.android.support:recyclerview-v7:27.1.1'
然后点击顶部的Sync Now进行同步
在activity_main.xml添加如下内容使用
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
这里我们简单实现如下界面
这和上面ListView实现的界面差不多。
照样写一个Fruit实体类,然后写一个子项布局fruit_item.xml
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 void setName(String name) {
this.name = name;
}
public int getImageId() {
return imageId;
}
public void setImageId(int imageId) {
this.imageId = imageId;
}
}
<?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="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"/>
</LinearLayout>
然后为RecyclerView准备一个适配器FruitAdapter类,让这个类继承RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder,其中ViewHolder是我们在FruitAdapter中定义的一个内部类。
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruitImage;
TextView fruitName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image);
fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {//创建ViewHolder实例,并将fruit_item布局加载进来
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.fruit_item,parent,false
);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {//对子项数据赋值
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {//返回子项的数目
return mFruitList.size();
}
}
最后我们修改MainActivity.java的代码。
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();//初始化水果数据
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);//LayoutManger用于指定RecyclerView的布局方式,这里LinearLayoutManger是线性布局的意思
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for(int i = 0;i < 2; i ++){
Fruit apple = new Fruit("Apple",R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("banana",R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("banana",R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("watermelon",R.drawable.watermelon_pic);
fruitList.add(watermelon);
}
}
}
实现横向滚动和瀑布流布局
实现横向滚动,还是对上面的代码进行操作,效果如下。
我们要对子项布局fruit_item.xml进行布局上的些许修改,因为目前这个布局的元素是水平排列的,适合纵向滚动,我们要把子项布局中元素改为纵向排列才比较合理。
fruit_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
</LinearLayout>
然后修改MainActivity.java的代码
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);//设置布局的排列方向,默认纵向布局
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for(int i = 0;i < 2; i ++){
Fruit apple = new Fruit("Apple",R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("banana",R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("banana",R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("watermelon",R.drawable.watermelon_pic);
fruitList.add(watermelon);
}
}
}
除了LinearManger之外,RecyclerView还给我们提供了GirdLayoutManger和StaggeredGirLayoutManger两种内置的布局方式,GirdLayoutManger可以用来实现网格布局,StaggeredGirLayoutManger可以用于实现瀑布流布局。
下面我们先实现下瀑布流布局。
效果如下
还是先修改下子项布局fruit_item.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">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp"/>
</LinearLayout>
然后修改MainActivity.java
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new
StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);//第一个参数是布局列数,第二个参数是布局的排列方向
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for(int i = 0;i < 2; i ++){
Fruit apple = new Fruit(getRandomLengthName("Apple"),R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit(getRandomLengthName("banana"),R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit(getRandomLengthName("banana"),R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit(getRandomLengthName("watermelon"),R.drawable.watermelon_pic);
fruitList.add(watermelon);
}
}
private String getRandomLengthName(String name){//随机生成1-20之间的数,将字符串重复几遍,更好的显示布局效果
Random random = new Random();
int length = random.nextInt(20) + 1;
StringBuilder builder = new StringBuilder();
for(int i = 0;i < length;++ i){
builder.append(name);
}
return builder.toString();
}
}
RecyclerView的点击事件
它并没有提供现有的监听器供我们使用,而是需要我们自己给子项具体的View去注册事件。
我们修改FruitAdapter.java中的代码
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImage;
TextView fruitName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fruitView = itemView;
fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image);
fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull 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(){
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(view.getContext(),"you clicked view " + fruit.getName(),
Toast.LENGTH_SHORT).show();
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(view.getContext(),"you clicked image " + fruit.getName(),
Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
}
我们先是在ViewHolder中添加fruitView来保存子项最外层的布局实例,然后注册点击事件,这里将最外层的布局和ImageView都注册了点击事件。在点击事件中,先是获取用户点击的positon,然后通过position获取Fruit实例,在用Toast弹出信息。
WebView
借助它我们可以在自己的应用程序里嵌套一个浏览器,从而非常轻松的来展示各种各样的网页。
例子,在应用内打开百度。新建一个WebViewTest项目
修改activity_main.xml代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
然后修改MainActivity代码
借助getSettings()方法可以去设置一些浏览器的属性,这里我们并不去设置过多属性,只是调用setJavaScriptEnabled()方法来让WebView支持JavaScript脚本
然后调用WebView的setWebViewClient()方法,并传入一个WebViewClient实例,这段代码的作用是,当需要从一个网页跳转到另一个网页时,我们希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。最后就是调用WebView的loadUrl()方法并将网址传入,即可展示相应的内容。
另外本程序使用到了网络功能,而访问网络是需要声明权限的,因此我们还得修改AndroidManifest.xml文件,并加入权限声明,并且android10.0对未加密的流量不信任,需要再加入新的限制,我么需要在<aplication 标签内 设置usesCleartextTraffic 属性为true
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.webview">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:usesCleartextTraffic="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这样就可以访问百度了。
ScrollView—让你的布局滚动起来
简介
ScrollView称为滚动视图,当在一个屏幕的像素显示不下绘制的UI控件时,可以采用滑动的方式,使控件显示。
先看下ScrollView类的继承关系:
java.lang.Object
↳android.view.View
↳android.view.ViewGroup
↳android.widget.FrameLayout
↳android.widget.ScrollViewz
可以看出,ScrollView原来是一个FrameLayout的容器,不过在他的基础上添加了滚动,允许显示的比实际多的内容。
使用方式
1.竖直滚动视图ScrollView
在页面的竖直方向线性布局5个Button,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="内容一"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:gravity="center"
android:text="内容二"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:gravity="center"
android:text="内容三"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:gravity="center"
android:text="内容四"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:layout_marginBottom="80dp"
android:gravity="center"
android:text="内容五"
android:textColor="#03A9F4"
android:textSize="24sp" />
</LinearLayout>
</ScrollView>
通过Android Studio的Preview视图也可以看出,5个Button已超出屏幕显示,在不使用ScrollView的情况下,父布局直接使用LinearLayout,是无法使屏幕滑动显示所有控件的。
使用ScrollView后显示如下:
注意:ScrollView的子元素只能有一个,可以是一个View(如ImageView、TextView等) 也可以是一个ViewGroup(如LinearLayout、RelativeLayout等),其子元素内部则不再限制,否则会报以下异常。
Caused by: java.lang.IllegalStateException: ScrollView can host only one direct child
2.水平滚动视图HorizontalScrollView
在实际使用时,我们也会遇到水平方向,控件超出屏幕的情况。这时就需要使用水平方向的滚动视图HorizontalScrollView。
在上面代码头部新增一个HorizontalScrollView,水平方向线性布局4个ImageView,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="20dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="20dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="20dp"
android:src="@mipmap/ic_launcher" />
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="20dp"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
</HorizontalScrollView>
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:gravity="center"
android:text="内容一"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:gravity="center"
android:text="内容二"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:gravity="center"
android:text="内容三"
android:textColor="#03A9F4"
android:textSize="24sp" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="80dp"
android:layout_marginBottom="80dp"
android:gravity="center"
android:text="内容四"
android:textColor="#03A9F4"
android:textSize="24sp" />
</LinearLayout>
</ScrollView>
可以看出,HorizontalScrollView中的图片内容,可以横向滑动,并且整个布局由于外部嵌套了ScrollView,整体页可以竖直方向滑动。
注意:同ScrollView,HorizontalScrollView中的子元素也只能有一个,否则报错。
XML中常用属性介绍
1.android:fadingEdge=“none”
设置拉滚动条时,边框渐变的方向。none(边框颜色不变),horizontal(水平方向颜色变淡),vertical(垂直方向颜色变淡)。
2.android:overScrollMode=“never”
删除ScrollView拉到尽头(顶部、底部),然后继续拉出现的阴影效果,适用于2.3及以上的 否则不用设置。
3.android:scrollbars=“none”
设置滚动条显示,none(隐藏),horizontal(水平),vertical(垂直)。
4.android:descendantFocusability=""
该属性是当一个为view获取焦点时,定义ViewGroup和其子控件两者之间的关系。
属性的值有三种:
beforeDescendants //viewgroup会优先其子类控件而获取到焦点
afterDescendants //viewgroup只有当其子类控件不需要获取焦点时才获取焦点
blocksDescendants //viewgroup会覆盖子类控件而直接获得焦点
5.android:fillViewport=“true"
这是 ScrollView 独有的属性,用来定义 ScrollView 对象是否需要拉伸自身内容来填充
viewport。通俗来说,就是允许ScrollView去填充整个屏幕。比如ScrollView嵌套的子控件高度达不到屏幕高度时,虽然ScrollView高度设置了match_parent,也无法充满整个屏幕,需设置android:fillViewport=“true"使ScrollView填充整个页面,给ScrollView设置背景颜色就能体现。
常用方法:
滑动开关控制
scrollView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
// true禁止滑动 false可滑动
return true;
}
});
滑动位置控制
scrollView.post(new Runnable() {
@Override
public void run() {
//滑动到顶部
scrollView.fullScroll(ScrollView.FOCUS_UP);
//滑动到底部
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
滑动到某个位置
scrollView.post(new Runnable() {
@Override
public void run() {
//偏移值
int offset = 100;
scrollView.smoothScrollTo(0, offset);
}
});
结语
可以看出,ScrollView是在日常开发中经常使用的View控件,其使用方式也比较简单。