Android开发基础知识整理之UI与Fragment

本篇主要涉及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布局。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值