Android开发基础知识整理之UI与Fragment
来源:互联网 发布:小学网络教学 编辑:程序博客网 时间:2024/06/17 12:02
本篇主要涉及Android中UI开发和碎片的使用。
一、 UI开发
(一) 常见控件的使用
1. TextView
android:gravity
指定文字对其方式,可选值有top、bottom、left、right、center等。
2. Button
- 匿名类方式注册监听器
button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 相应逻辑 }});
- 实现接口方式注册监听器
public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(bundle savedInstanceState) { ... Button button = (Button) findViewById(R.id.button); button.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.button: // 相应逻辑 break; default: break; } }}
3. EditText
android:hint
设置提示性文本android:maxLines
设置最大行数获取输入的内容:
String inputText = editText.getText().toString();
4. ImageView
android:src="@drawable/img_1"
指定图片- 动态更改图片:
imageView.setImageResource(R.drawable.img_2);
5. ProgressBar
android:visibility
设置控件的可见属性,默认visible
表示可见,invisible
表示不可见但占据着原来的位置(透明状态),gone
表示不可见且不占用任何屏幕空间。- 通过代码设置可见属性:
if (progressBar.getVisibility() ==View.VISIBLE) { progressBar.setVisibility(View.GONE);}
- 通过style属性可以指定不同样式。
style="?android:attr/progressBarStyleHorizontal"
- 通过
android:max="100"
给进度条设置一个最大值,然后可在代码中动态更改进度:
int progress = progressBar.getProgress();progress = progress + 10;progressBar.setProgress(progress);
6. AlertDialog
- 通过AlertDialog.Builder创建一个AlertDialog实例,然后可以设置标题、内容、可否取消等属性,接下来调用
setPositiveButton()
方法为对话框设置确定按钮的点击事件,调用setNegativeButton()
方法设置取消按钮的点击事件,最后调用show()
方法将对话框显示出来。
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);dialog.setTitle("这是标题");dialog.setMessage("重要内容或警告信息");dialog.setCancelable(false);dialog.setPositiveButton("OK", new dialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { }});dialog.setNegativeButton("Cancel", new DialogInterface.OnClickLister() { @Override public void onClick(DialogInterface dialog, int which) { }});dialog.show();
7. ProgressDialog
- 与AlertDialog类似,也是构建一个ProgressDialog对象,然后设置标题、内容、可否取消等,最后通过
show()
方法显示出来。 - 调用
dismiss()
方法关闭对话框;
(二) 四种基本布局
1. 线性布局 (LinearLayout)
android:orientation
指定排列方向,可选vertical或horizontal;android:layout_gravity
指定控件在布局中的对齐方式,可选值有top、bottom、center_viertical、left、right等;android:layout_weight
可以按比例控制控件大小;
2. 相对布局 (RelativeLayout)
android:layout_alignParentLeft
、android:layout_alignParentRight
、android:layout_alignParentTop
、android:layout_alignParentBottom
、android:layout_centerInParent
属性设置控件在父控件中的位置。android:above
、android:below
、android:toLeftOf
、android:toRightOf
设置控件间的相对位置。
3. 帧布局 (FrameLayout)
- 所有控件默认摆放在布局左上角,可使用
android:layout_gravity
设置对齐方式。
4. 百分比布局
- 包括PercentFrameLayout和PercentRelativeLayout,包含在
com.android.support:percent
库中。 app:layout_widthPercent
、app:layout_heightPercent
可直接指定控件在布局中所占百分比。
<Button android:id="@+id/button1" android:text="Button 1" android:layout_gravity="left|top" app:layout_widthPercent="50%" app:layout_heightPercent="50%" />
(三) 自定义控件
1. 引入布局
构建一个布局文件,在主活动的布局中使用 <include layout="@layout/title" />
引入。
2. 创建自定义控件
- 新建TitleLayout继承自LinearLayout,重写构造方法,借助LayoutInflater对自定义布局进行动态加载。
from(context)
方法构建出LayoutInflater对象inflate(要加载的布局文件id, 父布局)
进行动态加载
- 加入相应逻辑。
- 在布局文件中添加,需要指明完整类名。
public class TitleLayout extends LinearLayout { public TitleLayout(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.title, this); Button titleBack = (Button) findViewById(R.id.title_back); titleBack.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ((Activity) getContext()).finish(); }); }}
<com.example.uicostomviews.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content" />
(四) ListView
1. 基本用法
借助适配器ArrayAdapter将数据传递给ListView:
- ArrayAdapter构造函数中传入三个参数 (当前上下文、ListView子项布局id、数据)。
- 调用ListView的
setAdapter()
方法将适配器传入。
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);
2. 定制界面
(1) 定义一个实体类作为Adapter的适配类型
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; }}
(2) 为ListView子项建立自定义布局
<!-- fruit_item.xml --><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" /> <TextView android:id="@+id/fruit_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_verticlal" android:layout_marginLeft="10dp" /></LinearLayout>
(3) 创建自定义适配器
重写构造函数和 getView()
方法,getView()会在每个子项滚动到屏幕内时被调用。
public class FruitAdapter extends ArrayAdapter<Fruit> { private int resourceId; // 重写构造函数 public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) { super(context, textViewResourceId, objects); resourceId = textViewResourceId; } // 重写getView()方法 @Override public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); // 获取当前项的Fruit实例 View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false); // 第三个参数表示只让父布局的Layout属性生效,但不为这个View添加父布局 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;}
(4) 在MainActivity中创建Adapter对象并传递给ListView
public class MainActivity extends AppCompatActivity { private List<Fruit> fruitList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { ... initFruit(); // 初始化水果数据的方法 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() { ... Fruit apple = new Fruit("Apple", R.drawable.apple_pic); fruitList.add(apple); ... }}
3. 优化
- 解决重复加载布局:
getView()
中convertView参数会将之前加载好的布局进行缓存,便于之后重用。 - 解决重复findViewById获取控件实例:新增内部类ViewHolder对控件实例进行缓存。
public View getView(int position, View convertView, ViewGroup parent) { Fruit fruit = getItem(position); 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); view.setTag(viewHolder); // 将ViewHolder存储在View中 } else { view = convertView; viewHolder = (ViewHolder) view.getTag(); // 重新获取ViewHolder } viewHolder.fruitImage.setImageResource(fruit.getImageId()); viewHolder.fruitName.setText(fruit.getName()); return view;}class ViewHolder { ImageView fruitImage; TextView fruitName;}
4. 点击事件
使用 setOnItemClickListener()
方法注册监听器,点击子项时回调 onItemClick()
方法,重写此方法加入点击事件的处理逻辑。
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(); }});
(五) RecyclerView
1. 基本用法
- 新建适配器FruitAdapter继承自RecyclerView.Adapter,并将泛型指定为FruitAdapter.ViewHolder。
- 定义一个内部类ViewHolder继承自Recycler.ViewHolder,构造函数传入一个View参数,通过findViewById获取布局中控件实例;
- 适配器的构造函数用于将数据数据源传进来;
- 重写
onCreateViewHolder()
、onBindViewHolder()
、getItemCount()
这三个方法;
- MainActivity中创建LinearLayoutManager对象,并调用
setLayoutMangager()
设置到RecyclerView中,再创建适配器实例并调用setAdapter()
完成适配器设置。
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(); }}
public class MainActivity extends AppCompatActivity { private List<Fruit> fruitList = new ArrayList<>(); @Override protect void onCreate(Bundle savedInstanceState) { ... initFruits(); // 初始化水果数据 RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); LinearLayoutManager layoutManager = new LinearManager(this); recyclerView.setLayoutManager(layoutManager); FruitAdapter adapter = new FruitAdapter(fruitList); recyclerView.setAdapter(adapter); } private void initFruits(){ // 将水果数据添加到fruitList中 }}
2. 横向滚动、网格布局和瀑布流布局
(1) 横向滚动
- 要实现横向滚动,需把fruit_item里的元素改为垂直排列。
- 调用LinearLayoutManager的
setOrientation()
来设置布局排列方向。
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
(2) 网格布局
- 使用GridLayoutManager,构造函数接收两个参数:(Context, 列数) 。
GridLayoutManager layoutManager = new GridLayoutManager(this, 2); // 两列的网格布局recyclerView.setLayoutManager(layoutManager);
(3) 瀑布流布局
- 使用StaggeredGridLayoutManager,构造函数接收两个参数:(列数, 排列方向) 。
StaggeredGridLayoutManager layoutManager = new StaggeredLayoutManager(3, StaggeredGridLayoutManager.VERTICAl); // 三列、纵向排列recyclerView.setLayoutManager(layoutManager);
3. 点击事件
需要在 onCreateViewHolder()
中自己给子项具体的View去注册点击事件。
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHoder> { ... @Override public 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.fruitImage.setOnclickListener(new OnClickListener() { @Override public void onClick(View v) { int position = holder.getAdapterPosition(); Fruit fruit = mFruitList.get(position); Toast.makeText(v.getContext(), "点击了图片" + fruit.getName(), Toast.LENGTH_SHORT).show(); } }); return holder; } ...}
二、 Fragment
(一) 碎片的使用
1. 基本用法
- 创建碎片的布局文件;
- 新建类继承自Fragment,重写
onCreateView()
方法; - 在主活动的布局文件中添加
<fragment>
标签,需要通过android:name
指明添加的碎片完整类名(带包名)。
public class MyFragment extends Fragment { @Override public View onCreateView(LayoutInflate inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.my_fragment, container, false); return view; }}
<fragment android:id="@+id/my_fragment" android:name="com.example.fragmenttest.MyFragment" android:layoutwidth="0dp" android:layout_height="match_parent" android:layout_weight="1" />
2. 动态添加碎片
(1) 创建待添加碎片实例;
(2) 调用getSupportFragmentManager()
方法获取FragmentManager;
(3) 调用 beginTransaction()
开启一个事务;
(4) 调用 replace()
方法向容器内添加或替换碎片,需传入 (容器id, 碎片实例);
(5) 调用 commit()
方法提交事务。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { ... Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { replaceFragment(new AnotherFragment()); // 替换为另一个碎片 } }); replaceFragment(new MyFragment()); // 初始设置为MyFragment } private void repalceFragment(Fragment fragment) { FragmentManager fragmentmanamger = getSupportFragmentManager(); FragmentTransaction transaction = fragmentManager.beginTransaction(); transaction.repalce(R.id.right_layout, fragment); transaction.commit(); }}
3. 碎片中模拟返回栈
调用 addToBackStack()
方法将事务添加到返回栈中,它接收一个名字用于描述返回栈状态,一般传入null即可,这样按下Back键会回到上一个Fragment界面。
FragmentManager fragMentmanager = getSupportFragmentManager();FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.replace(R.id.right_layout, fragment);transaction.addToBackStack(null); // 添加到返回栈transaction.commit();
4. 碎片和活动间进行通信
- 活动中调用碎片里的方法:使用FragmentManager的
findFragmentById
获取碎片实例,即可调用其中方法。 - 碎片中调用活动里的方法:使用
getActivity()
得到和当前碎片关联的活动实例,即可调用其中方法。
MyFragment myFragment = (MyFragment) getFragmentManager().findFragmentById(R.id.my_fragment); // 活动中获取碎片实例
MainActivity activity = (MainActivity) getActivity(); // 碎片中获取活动实例
(二) 碎片的生命周期
与活动生命周期类似,并提供了一些的附加的回调方法:
onAttach()
:当碎片和活动建立关联时调用。onCreateView()
:为碎片创建视图(加载布局)时调用。onActivityCreated()
:确保与碎片关联的活动一定已创建完毕时调用。onDestroyView()
:当与碎片关联的视图被移除时调用。onDetach()
:当碎片和活动解除关联时调用。
碎片中也可以通过 onSaveInstanceState()
方法保存数据,保存的数据在 onCreate()
、onCreateView()
、onActivityCreated()
中都可以得到。
(三) 动态加载布局技巧
1. 使用限定符
- 屏幕大小:small、normal、large、xlarge
- 屏幕分辨率:ldpi、mdpi、hdpi、xhdpi、xxhdpi
- 方向:land、port
2. 使用最小宽度限定符(Smallest-width Qualifier)
res目录下新建layout-sw600dp文件夹,在其中新建acticity_main.xml布局。
- 屏幕宽度大于600dp的设备:加载layout-sw600dp/activity_main布局
- 屏幕宽度小于600dp的设备:仍会加载默认的layout/activity_main布局。
- Android开发基础知识整理之UI与Fragment
- Android UI开发详解之Fragment
- Android UI开发详解之Fragment
- Android UI开发详解之Fragment
- Android UI开发详解之Fragment
- Android UI开发详解之Fragment
- Android基础知识之Fragment
- Android开发基础知识整理之四大组件
- Android开发基础知识整理之数据存储
- Android开发之利用Fragment建立动态UI
- Android UI高级之Fragment
- Android中UI之Fragment
- 【Android开发】之Fragment与Acitvity通信
- Android开发基础知识整理之多线程与网络技术
- Android官方开发文档Training系列课程中文版:使用Fragment构建动态UI之Fragment创建
- Fragment基础知识整理
- 《android编程权威指南》学习笔记之第七章 UI fragment与fragment管理器
- Android开发之Fragment
- PSI授权HTTPS
- python 集合set的创建,更改,遍历,元算合并,交集,补集
- #分数阶Fourier变换的总体认知(From 陶然著)
- [生存志] 第114节 韩信围垓下
- 挨踢部落第二期:大数据在医疗领域的应用和实践
- Android开发基础知识整理之UI与Fragment
- 写程序输出8皇后问题的所有排列,要求使用非递归的深度优先遍历。
- HDU 1556 树状数组
- HTTP协议之报文格式
- 第一个Hello Vue!
- 在8X8的棋盘上分布着n个骑士,他们想约在某一个格中聚会。骑士每天可以像国际象棋中的马那样移动一次,可以从中间像8个方向移动(当然不能走出棋盘),请计算n个骑士的最早聚会地点和要走多少天。要求尽早聚会
- 集合框架线程同步
- git修改远程仓库地址
- Android webview使用详解