xml布局
<Button>布局里所有的英文单词会自动进行大小写转化,可以通过配置,更改这一选项。
<EditText>布局里可以设置行数
通过<Button>获取到<EditText>中的内容
点击效果如下:
<ImageView>
在运行界面动态更改图片,代码如下:
<ImageView
android:id="@+id/pic"
android:src="@mipmap/pic_1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
@Override
public void onClick(View view) {
imageView.setImageResource(R.mipmap.pic_2);
}
在mipmap中传入两张图片pic_1,pic_2.在布局文件中为ImageView设置src为pic_1,在java文件的点击事件
中中通过
setImageResource()方法调用pic_2,运行程序结果如下:
点击按钮之后的效果如下:
<ProgressBar>
如何让进度条在加载完之后消失。可以利用控件的可见属性。android:visibility进行指定。可选值有3种
1.visible[可见的] 2.invisible[不可见的,但任然占据原来的位置和大小] 3.gone[不可见,且不占用任何的屏幕空间]
以上可以通过代码实现。设置点击按钮让进度条消失,再次点击就出现的效果。
@Override public void onClick(View view) { if (progressBar.getVisibility()==View.GONE){ progressBar.setVisibility(View.VISIBLE); }else { progressBar.setVisibility(View.GONE); } }
在按钮的点击事件中,通过getVisibility()方法来判断ProgressBar是否可见。如果不可见就将它显示
出来
如果可见,就将它影藏。
运行结果:
点击按钮:
再次点击:
<ProgressBar>还可以设置不同的样式,
<ProgressBar
android:max="100"
style="?android:attr/progressBarStyleHorizontal"
设置进度条为水平进度条,并给定它的最大值是100.
@Override public void onClick(View view) { int progress=progressBar.getProgress(); progress=progress+10; progressBar.setProgress(progress); }
每点击一次按钮,就获取当前的进度,然后在现有的进度上+10,运行结果如下:
点击一次:
点击10次:
AlertDialog
AlertDialog可以在当前界面弹出一个对话框,它置于所有界面元素之上,能屏蔽掉其他控件的交互能力。一般用于
提示一些非常重要的内容或者警告信息。
代码如下:
@Override
public void onClick(View view) {
AlertDialog.Builder dialog=new AlertDialog.Builder(FirstActivity.this);
dialog.setTitle("This is a Dialog");
dialog.setMessage("Something important!");
dialog.setCancelable(false);
dialog.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
dialog.setNegativeButton("Cancle", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
dialog.show();
}
首先通过AlertDialog.Builder创建一个AlertDialog的实例,然后可以为这个对话框设置标题,内容,
可否取消等属性
,接下来调用setPositiveButton()方法为对话框设置确定按钮的点击事件,调用setNegativeButton()方法设置取消按钮的点击事件
最后调用show()方法将对话框显示出来。
ProgressDialog
ProgressDialog和AlertDialog有点类似,都可以在界面上弹出一个对话框,都能屏蔽其他控件的交互能力。不同的是
ProgressDialog会在对话框中显示一个进度条,一般用于表示当前的操作比较耗时,他们的用法也比较相似。
代码如下:
@Override
public void onClick(View view) {
ProgressDialog progressDialog=new ProgressDialog(FirstActivity.this);
progressDialog.setTitle("This is a ProgressDialog");
progressDialog.setMessage("Loading.....");
progressDialog.setCancelable(false);
progressDialog.show();
}
这里也是先构建出一个ProgressDialog对象,然后可以设置标题,内容,是否取消等属性。最后也需要
show()方法将它显示出来。注意,当setCancelable()方法设置为false,运行时则无法通过BACK键取消,需要在代码中调用ProgressDialog.dissmiss()方法来关闭。
运行结果如下:
4种基本布局
LinearLayout线性布局
gravity与layout_gravity的区别:gravity用于指定文字在控件中的对齐方式,layout_gravity用于指定控件在
布局中的对齐方式。它们的可选值差不多,但需要注意,当LinearLayout设置为horizontal时,layout_gravity只有
垂直方向的对齐才会生效,同理,为vertical时,只有水平的方式才会生效。
只有LinearLayout布局支持layout_weight
RelativeLayout相对布局
FrameLayout帧布局
百分比布局
创建自定义控件
引入布局:
通过引入布局创建标题栏。
创建一个title.xml文件,在里面写入布局。
<Button
android:id="@+id/title_back"
android:text="back"
android:layout_margin="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:gravity="center"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/title_text"
android:layout_weight="1"
android:text="Title Text"
android:textSize="24sp"
android:layout_marginTop="5dp"
android:textColor="#000"/>
<Button
android:layout_width="wrap_content"
android:id="@+id/Title_edit"
android:layout_margin="5dp"
android:text="Edit"
android:textColor="#fff"
android:layout_height="wrap_content" />
</LinearLayout>
再创建一个Activity,在它的布局文件中写下如下代码
之后再在他的java文件中写入一串代码,用于去掉系统自带的标题栏
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uicustom_views);
ActionBar actionBar=getSupportActionBar();
if (actionBar!=null){
actionBar.hide();
}
}
运行结果如下:
使用这种方法,不管多少布局需要添加标题栏,只需一行include语句就可以了。
创建自定义控件
引入布局的技巧解决了重复编写布局代码的问题,但如果布局中的一些控件要求能够响应事件,我们还是需要在每一个活动中为这些控件单独编写一次事件注册代码。比如标题栏的返回按钮,其实不管在哪一个活动中,它的功能都是相同的,即销毁当前活动。
但如果每一次都重新注册会增加很多重复代码,这种情况最好使用自定义控件。
新建TitleLayout继承LinearLayout,让它成为我们自定义的标题栏控件,代码如下:
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
}
首先重写LinearLayout中带有两个参数的构造函数,在布局中引入TitleLayout控件就会调用这个构造函数,
之后在构造函数中对布局进行动态加载,这需要借助LayoutInflater来实现。通过LayoutInflater的from()
方法可以构建出一个LayoutInflater对象,然后调用inflate()方法就可以动态加载一个布局文件。
inflate()方法接收两个参数,第一个是加载的布局id,第二个是给加载好的布局再添加一个父布局,
这里指定为TitleLayout,于是直接传入this。
自定义控件已经创建好了,我们需要在布局文件中添加这个自定义控件,修改UICustomViews。xml中的代码,如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.example.newstartingpoint.TitleLayout
android:layout_height="match_parent"
android:layout_width="wrap_content" />
</LinearLayout>
在添加自定义控件的时候需要指明控件完整的类名,包名是不可以省略的,
修改TitleLayout中的代码:
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
titleBack=findViewById(R.id.title_back);
titleEdit=findViewById(R.id.title_edit);
titleBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
((Activity) getContext()).finish();
}
});
titleEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(),"You clicked Edit button",Toast.LENGTH_SHORT).show();
}
});
}
运行结果如下:
按下Edit:
按下BACK按钮直接退出。
最常用和最难用的控件,ListView
在MainActivity中添加一个ListView,并且给一个id。
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
接下来修改MainActivity中的代码,
public class MainActivity extends AppCompatActivity {
private ListView listView;
private String[] data = {"Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple",
"Strawberry", "Cherry", "Mango", "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple",
"Strawberry", "Cherry", "Mango", "Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape", "Pineapple",
"Strawberry", "Cherry", "Mango"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
MainActivity.this, android.R.layout.simple_list_item_1, data);
listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}
ListView是用于展示大量数据的,我们应该先将数据提供好,数据可以从网上下载,可以从数据库中读取,视
具体场景而定。这里简单使用一个data数组来测试。
数组中的数据是无法直接传递给ListView的,需要借助适配器来实现,android提供了很多种,这里使用ArrayAdapter,
它可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。ArrayAdapter有多个构造函数的重载,应该根据实际情况选择,此处我们提供的字符串,因此将ArrayAdapter的泛型指定为String,然后在ArrayAdapter的构造函数中依次传入当前的上下文,ListView子项布局的id,以及要适配的数据。这里我们使用android.R.layout.simple_list_item_1作为ListView的子项布局id。这是一个Android内置的布局文件,里面只有一个TextView.可用于简单的显示一段文本。
最后调用setAdapter()方法,将构建好的适配器对象传递进去,ListView和数据之间的关联就建立完成了。
运行结果如下:
可通过上下滑动查看数据
定制ListView界面
将上段ListView的文字添加图片。
首先定义一个实体类,作为ListView适配器的适配类型。新建类Fruit。代码如下:
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类只有两个字段,name表示水果名字,imageId表示水果对应的图片资源id。然后需要为ListView的子项指定一个我们自定义的布局。在layout目录下新建fruit_item.xml,代码如下:<ImageView
android:id="@+id/fruit_image"
android:layout_width="100dp"
android:layout_height="100dp" />
<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" />
这个布局中我们定义一个ImageView和<TextView>用于显示图片和水果名称。接下来需要创建一个自定义的适配器,继承自ArrayAdapter,并将泛型指定为Fruit,新建类FruitAdapter,代码如下:
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
public FruitAdapter(@NonNull Context context, int textViewResourceId, List<Fruit> objects) {
super(context,textViewResourceId,objects);
resourceId=textViewResourceId;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit=getItem(position);//获取当前的Fruit实例
View view= LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
ImageView fruitImage=(ImageView)view.findViewById(R.id.fruit_image);
TextView fruitName=(TextView)view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
}
FruitAdapter重写了父类的一组构造函数,用于将上下文,ListView子项布局的id和数据,都传递进来
,另外又重写了getView()方法,这个方法在每个子项被滚到屏幕内的时候会被调用。在getView()方法中,首先通过getItem()方法得到当前项的Fruit实例,然后使用LayoutInflater来为这个子项加载我们传入的布局。
LayoutInflater的inflate()方法接收3个参数,1.上下文环境 2.ListView子项布局的id 第三个参数指定
成false,表示只让我们在父布局中声明layout属性生效,但不为这个View添加父布局。一旦View有了父
布局之后,它就不能再添加到ListView中了,
调用View的findViewById()方法分别获取到ImageView和TextView的实例,并分别调用它们的
setImageResource()和setText()方法来设置显示的图片和文字。最后将布局返回。
修改MainActivity中的代码。
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.list_view);
listView.setAdapter(adapter);
}
private void initFruits() {
for (int i=0;i<4;i++){
Fruit apple=new Fruit("Apple",R.mipmap.pic_1);
fruitList.add(apple);
Fruit banana=new Fruit("Banana",R.mipmap.pic_2);
fruitList.add(banana);
Fruit pear=new Fruit("Pear",R.mipmap.ic_launcher);
fruitList.add(pear);
}
}
}
这里添加了一个initFruits()方法,用于初始化所有的水果数据。在Fruit类的构造函数中将水果的名字
和对应的图片id传入。然后把创建好的对象添加到水果列表中。另外用一个for循环将所有的水果数据添加4遍。接着在onCreate()方法中创建FruitAdapter对象。并将FruitAdapter作为适配器传递给ListView.
运行结果如下: