第一行代码读书笔记
常用控件
TextView
<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"/>
layout_width&layout_height- Android中的所有控件都具有这两个属性
match_parent/fill_parent/wrap_content
gravity- 指定文字的对齐方式
top/bottom/left/right/center...- 可以用
|来同时指定多个值 - center == center_vertical | center_horizontal
textSize- 指定文字的大小
- 使用sp作为单位
textColor- 指定文字的颜色
- etc
Button
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false"/>
textAllCaps- 所有英文字母自动转换为大写
@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 v) {
// TODO
}
});
}
- 在onCreate()中为Button点击事件注册监听器
- 匿名类方式
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 v) {
switch (v.getId()) {
case R.id.button:
// TODO
break;
default:
break;
}
}
}
- 用实现接口的方式注册监听器
EditText
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2"
/>
hint- 指定提示性的文本
maxLines- 指定最大行数
- 输入的内容超过指定行数后文本会向上滚动,不再继续wrap拉伸
getText().toString()- 获取文本框中输入的内容
ImageView
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img"
/>
srcsetImageResource()
ProgressBar
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
/>
style- 指定样式
- ?android:attr/progressBarStyleHorizontal:水平样式
max- 设置最大值,然后在代码中动态地更改进度条的进度
visibilityvisible:可见invisible:不可见但仍然占据原来的位置和大小gone:不可见且不占用哦那个原来的位置和大小
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
if (progressBar.getVisibility() == View.GONE){
progressBar.setVisibility(View.VISIBLE);
} else {
progressBar.setVisibility(View.GONE);
}
int progress = progressBar.getProgress();
progress = progress + 10;
progressBar.setProgress(progress);
break;
default:
break;
}
}
AlertDialog
- 在当前的界面弹出一个对话框,置顶于所有界面元素之上,能够屏蔽其他控件的交互能力
@Override
public void onClick(View v) {
switch (v.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 dialog, int which) {
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
break;
default:
break;
}
}
- 标题、内容、可否取消等属性
setPositiveButton():确认按钮的点击事件setNegativeButton():取消按钮的点击事件
ProgressDialog
- 弹出一个对话框,屏蔽掉其他控件的交互能力,显示进度条
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button:
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
dialog.setTitle("This is ProgressDialog");
dialog.setMessage("Loading...");
dialog.setCancelable(true);
dialog.show();
break;
default:
break;
}
}
setCancelable()- false:不能通过Back键取消,加载完必须调用ProgressDialog的
dismiss()来关闭对话框
- false:不能通过Back键取消,加载完必须调用ProgressDialog的
4种基本布局
线性布局 LinearLayout
- 包含的所有空间在线性方向上依次排列
orientation:指定排列方向vertical/default:horizontal- 如果排列方向是horizontal,控件宽度就不能指定为match_parent;反之亦然。
layout_gravity- 指定控件在布局中的对齐方式
- 如果排列方向是horizontal,只有垂直方向上的对齐方式才会生效;反之亦然。
layout_weight- 使用比例的方式指定控件的大小
- 可用于手机屏幕适配性
- 把LinearLayout下的所有控件的layout_width值相加得到总值
每个控件所占大小的比例就是该控件的layout_weight值除以总值 - wrap_content的控件仍按值计算,match_parent的控件占屏幕剩余的空间
相对布局 RelativeLayout
- 通过相对定位的方式让控件出现在布局的任何位置
- 控件相对于控件布局 E.g.
android:layout_above = @id/button layout_abovelayout_belowlayout_toLeftOflayout_toRightOf
layout_alignToplayout_alignBottomlayout_alignLeftlayout_alignRight
帧布局 FrameLayout
- 所有控件都会默认摆放在布局的左上角
- 可以用
layout_gravity指定控件在布局中的对齐方式 - 应用较少
百分比布局 PercentFrameLayout/PercentRelativeLayout
- 允许直接指定控件在布局总所占的百分比
- 定义在support库中,在项目的build.gradle中添加依赖,就能保证百分比布局在安卓所有系统版本上的兼容性
-
<android.support.percent.PercentFrameLayout 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"> </android.support.percent.PercentFrameLayout> app:layout_widthPercent
app:layout_heightPercent
AbsoluteLayout TableLayout etc.
自定义控件
- 新建布局title.xml(带自定义的标题栏的布局)
引入布局
<include layout="@layout/title"
将系统自带的标题栏隐藏掉
ActionBar actionbar = getSupportActionBar();
if (actionbar != null) {
actionbar.hide();
}
创建自定义控件
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title, this);
}
}
- 在布局文件中添加自定义控件
<com.example.uicustomviews.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content" />
ListView
- 允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内
同时屏幕上原有的数据会滚动出屏幕 - 最常用&最难用
简单用法
- 在布局中加入ListView
<ListView android:id="@+id/list_view" android:layout_width="match_parent" android:layout_height="match_parent" /> - 在MainActivity中添加数据
public class MainActivity extends AppCompatActivity { private String[] data = { "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 listView = (ListView) findViewById(R.id.list_view); listView.setAdapter(adapter); } }- 数组中的数据无法直接传递给ListView,借助适配器传递
- 在ArrayAdapter的构造函数中一次传入当前上下文、ListView的子项布局的id,以及要适配的数据
- android.R.layout.simple_list_item_1:Android内置的布局文件,里面只有一个TextView
- setAdapter():将构建好的适配器对象传递进去
传递类给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; } } - 为ListView的子项指定自定义布局
fruit_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 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> - 创建自定义适配器
public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceId; public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; } @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); 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; } }- LayoutInflater()的第三个参数
false:只让在父布局中声明layout属性生效,但不为这个View添加父布局
ListView的标准写法
- LayoutInflater()的第三个参数
提升ListView的运行效率
- FruitAdapter中getView()每次都将布局重新加载了一遍
getView()中有一个convertView参数,用于将之前加载好的布局进行缓存,以便之后重用View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); } else { view = convertView; }
etc.
ListView的点击事件
FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fruit fruit = fruitList.get(position);
Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
setOnItemClickListener为ListView注册一个监听器
当用户点击ListView中的任意子项时,回调onItemClick()方法
该方法通过position判断出用户点击的是哪个子项
RecyclerView
- 定义在support库中,在项目的build.gradle中添加依赖库
- 在dependencies闭包中添加:
compile 'com.android.support:recyclerview-v7:24.2.1'
基本用法
- 适配器
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> { private List<Fruit> mFruitList; static class ViewHolder extends RecyclerView.ViewHolder { ImageView fruitImage; TextView fruitName; public ViewHolder(View view) { super(view); fruitImage = (ImageView) view.findViewById(R.id.fruit_image); fruitName = (TextView) view.findViewById(R.id.fruit_name); } } public FruitAdapter(List<Fruit> fruitList) { mFruitList = fruitList; } @Override public 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; } @Override public void onBindViewHolder(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继承自RecyclerView.ViewHolder
ViewHolder的构造函数中要传入一个View参数,通常为RecyclerView子项的最外层布局onCreateViewHolder()用于创建ViewHolder实例onBindViewHolder用于对RecyclerView子项的数据进行赋值
LayoutManager用于指定RecyclerView的布局方式
LinearLayoutManager线性布局
GridLayoutManager网格布局
StaggeredGridLayoutManager瀑布流布局
横向滚动和瀑布流布局
-
横向滚动
- 把fruit_item.xml里的元素改成垂直排列
android:orientation="vertical"
android:layout_gravity="certer_horizontal"ListView的布局排列是由自身管理的, RecyclerView由LayoutManager管理
LayoutManager中制定了一套可扩展的布局排列接口
- 把fruit_item.xml里的元素改成垂直排列
-
瀑布流布局
recyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(layoutManager);
getRandomLengthName()使用Random对象创造一个1-20的随机数,然后将参数中传入的字符串重复随机遍
RecyclerView的点击事件
- 在
onCreateViewHolder()中注册点击事件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 v) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(v.getContext(), "you clicked view" + fruit.getName(), Toast.LENGTH_SHORT).show(); } }); holder.fruitImage.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(v.getContext(), "you clicked image" + fruit.getName(), Toast.LENGTH_SHORT).show(); } });- 分别为外层布局和ImageView注册了点击事件
其他
制作Nine-Patch图片(部分拉伸)
- 打开
draw9patch.bat文件,并把图片加载进来 - 在图片的四个边框绘制小黑点,拉伸时只拉伸黑点标记的区域
- 鼠标在边缘拖动绘制,按住Shift键拖动擦除