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_alignParentLeftandroid:layout_alignParentRightandroid:layout_alignParentTopandroid:layout_alignParentBottom
    android:layout_centerInParent 属性设置控件在父控件中的位置。
  • android:aboveandroid:belowandroid:toLeftOfandroid:toRightOf 设置控件间的相对位置。

3. 帧布局 (FrameLayout)

  • 所有控件默认摆放在布局左上角,可使用 android:layout_gravity 设置对齐方式。

4. 百分比布局

  • 包括PercentFrameLayout和PercentRelativeLayout,包含在 com.android.support:percent 库中。
  • app:layout_widthPercentapp: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布局。
0 0
原创粉丝点击