第二行代码第三章笔记

第三章 UI开发

使用XML编写程序界面

可视化编辑工具并不利于你去真正了解界面后面的实现原理,通过这种方式制作出的界面通常不具有很好的屏幕适配性,而且当需要编写较为复杂的界面时,可视化编辑工具很难胜任。

等你完全掌握了使用XML来编写界面的方法后,不管是进行高复杂度的界面实现,还是分析和修改当前现有的界面,对你来说都将是手到擒来。

常见控件的使用方法和属性

TextView

  • android:layout_width=控件的宽度

  • android:layout_height=控件的宽度

  • android:text显示的文本内容

  • android:gravity控件内文字对齐方式

  • android:textSize文字大小

  • android:textColor文字的颜色

  • android:gravity指定文字对齐方式(center/bottom/left/right/top)

Button

  • 按钮的点击事件

  • android:textAllCaps英文字母自动进行大写转换

EditText

  • android:hint提示性文本

  • android:maxLines最大行数

  • 点击事件的应用

  • editText.getText().toString()代码中获取EditText中输入内容

ImageView

  • android:src图片地址

  • 代码中改变图片内容imageView.setImageResource()

ProgressBar

  • 设置控件的可见性setVisibility()—-View.VISIBLE/View.INVISIBLE/View.GONE

  • sytle样式修改

AlertDialog

  • 通过AlertDialog.Builder创建出一个AlertDialog的实例

  • 设置对话框的标题、内容、可否用back取消等属性,setPositiveButton()设置确定按钮的点击事件,setNegativeButton()设置取消按钮的点击事件。

  • 调用show()方法显示对话框

ProgressDialog

  • 通过ProgressDialog.Builder创建出一个ProgressDialog的实例

  • 设置对话框的标题、内容、可否取消等。

  • 调用show()方法显示对话框

  • setCancelable()中传入false则无法通过BACK键取消.dismiss()关闭对话框

ToggleButton

  • android:checked当前是否被选中

  • android:textOn/android:textOff

  • 点击事件setOnCheckedChangeListener(),监听器onCheckedChanged()

CheckBox

  • android:checked当前是否被选中

  • 点击事件setOnCheckedChangeListener(),监听器onCheckedChanged();

RadioGroup与RadioButton

  • RadioGroup是RadioButton的一个集合,提供多选一机制

  • android:orientation决定当前RadioGroup中RadioButton以什么形式排列

  • 点击事件setOnCheckedChangeListener(),监听器选RadioGroup包中的onCheckedChanged();

四种基本布局

  1. LinearLayout线性布局

    • android:orientation—-horizontal横向/vertical垂直

    • android:gravity指定文字在控件中的对齐方式

    • android:layout_gravity指定控件在布局中的对齐方式

    • android:weight使用比例的方式指定控件大小

  2. RelativeLayout

    • android:alignParentLeft等

    • android:above/android:below

    • android:toLeftOf等

  3. FrameLayout

    • 所有空间都默认摆在布局的左上角,但是可以通过android:layout_gravity指定控件的对齐方式
  4. PercentFrameLayout和PercentRelativeLayout

    • 不能在使用wrap_content/match_parent指定控件大小,通过app:layout_widthPercent和app:layout_heightPercent指定控件大小

    • 添加百分比库的依赖com.android.percent:……

自定义控件

新建一个title.xml布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/title_bg">

    <Button
        android:id="@+id/title_back"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/back_bg"
        android:text="Back"
        android:textColor="#fff" />

    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_weight="1"
        android:gravity="center"
        android:text="Title Text"
        android:textColor="#fff"
        android:textSize="24sp" />

    <Button
        android:id="@+id/title_edit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="@drawable/edit_bg"
        android:text="Edit"
        android:textColor="#fff" />

</LinearLayout>

引入布局

  1. 在activity_main.xml中添加<include layout="@layout/title"/>

  2. 通过代码隐藏标题栏

ActionBar ac = getSupportActionBar();
if(ac != null){
   ac.hide();
}

创建自定义控件

如果布局中有一些控件要求响应时间,我们还需要在每个活动中为这些控件单独编写一次事件注册代码,这种情况最好使用自定义控件的方式来解决

  1. 新建TitleLayout继承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);
    Button titleEdit = (Button) findViewById(R.id.title_edit);
        titleBack.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                ((Activity) getContext()).finish();
            }
        });
        titleEdit.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show();
            }
        });
}
  1. 在布局文件中添加这个自定义控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <com.example.uicustomviews.TitleLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

难点控件ListView

ListView的简单用法

布局中加入ListView控件,将需要展示的数组数据提供好,需要借助适配器(ArrayAdapter)传递数组数据给ListVIew

ArrayAdapter<String>adapter = new ArrayAdapter (Context context, @LayoutRes int resource, Listobjects);
ListView listView =(ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);

ListView的定制界面用法

  1. 新建实体类Fruit作为ListView适配器的适配类型,Fruit类中有两个字段,name表示水果名称,imageId表示水果对应的图片资源id
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;}
}
  1. 为ListView的子项指定一个自定义的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    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_vertical"
        android:layout_marginLeft="10dp" />
</LinearLayout>
  1. 创建自定义的适配器,这个适配器继承自ArrayAdapter并将泛型指定为Fruit。重写了父类的一组构造函数,将上下文、ListView子项布局的id和数据都传递进来。重写getView()方法,这个方法在每个子项被滚动到屏幕内的时候会被调用。在getView()方法中首先通过getItem()方法得到当前项的Fruit实例,然后使用LayoutInflater来为资格子项加载我们传入的布局。
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); // 获取当前项的Fruit实例
        View view = = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
        ImageView fruitImage = (ImageView) view.findViewById (R.id.fruit_image);
        ImageName fruitName = (TextView) view.findViewById (R.id.fruit_name);
        fruitImage.setImageResource(fruit.getImageId());
        fruitName.setText(fruit.getName());
        return view;
    }
}
  1. 布局中加入ListView控件,初始化水果数据(在Fruit类的构造函数中将水果的名称和图片id传入,然后把创建好的对象添加到水果列表中),创建FruitAdapter对象,并将FruitAdapter作为适配器传递给ListView
    private List<Fruit> fruitList = new ArrayList<>();
    initFruits();//初始化水果数据
    FruitAdapter adapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
  1. 提升ListView的运行效率
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); // 获取当前项的Fruit实例
        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;
    }
}
  1. ListView的点击事件
public class MainActivity extends AppCompatActivity {
    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @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);
        //按钮的点击事件
        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. 添加依赖库

    compile 'com.android.support:recyclerview-v7:24.2.1'

  2. 布局中添加控件(使用和ListView一样的Fruit类和fruit_item.xml,代码略)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
       <android.support.v7.widget.RecyclerView
           android:id="@+id/recycler_view"
           android:layout_width="match_parent"
           android:layout_height="match_parent" />
    </LinearLayout>

  3. 准备一个适配器FruitAdapter继承RecyclerView.Adapter(重写onCreateViewHolder()/onBindViewHolder()/getItemCount()三个方法)并将泛型指定为FruitAdapter.ViewHolder,ViewHolder是FruitAdapter中定义的一个内部类。

public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

   private List<Fruit> mFruitList;

   static class ViewHolder extends RecyclerView.ViewHolder {
       ImageView fruitImage;
       TextView fruitName;

      //ViewHolder构造函数中,传入的View参数通常就是RecyclerView子项的最外层布局
       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;
       }

     //用于创建ViewHolder实例,并把加载处理的布局传入到函数当中,最后将ViewHolder的实例返回
       @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;
       }

     //该方法用于对RecyclerView的子项进行复制,会在每个子项被滚动到屏幕内的时候执行,通过position参数得到当前项的Fruitshili,然后在将数据设置到ViewHolder的ImageView和TextView当中
       @Override
       public void onBindViewHolder(ViewHolder holder, int position) {
           Fruit fruit = mFruitList.get(position);
           holder.fruitImage.setImageResource(fruit.getImageId());
           holder.fruitName.setText(fruit.getName());
       }

     //用于告诉RecyclerView一共有多少子项,直接返回数据源的长度就可以
       @Override
       public int getItemCount() {
           return mFruitList.size();
       }
   }

  1. 使用initFruits()方法初始化水果数据
public class MainActivity extends AppCompatActivity {

    private List<Fruit> fruitList = new ArrayList<Fruit>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      //先使用initFruits()方法初始所有的水果数据
        initFruits();
      //接着获取到RecyclerView的实例
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
      //然后创建一个LinerLayoutManager的对象,并将它设置到RecyclerView当中,
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
      //创建FruitAdapter的实例,并将水果数据传入到FruitAdapter的构造函数中
        FruitAdapter adapter = new FruitAdapter(fruitList);
      //完成最后适配器设置
        recyclerView.setAdapter(adapter);
    }

    private void initFruits() {
        for (int i = 0; i < 2; i++) {
            Fruit apple = new Fruit(getRandomLengthName("Apple"), R.drawable.apple_pic);
            fruitList.add(apple);
            Fruit banana = new Fruit(getRandomLengthName("Banana"), R.drawable.banana_pic);
            fruitList.add(banana);
            Fruit orange = new Fruit(getRandomLengthName("Orange"), R.drawable.orange_pic);
            fruitList.add(orange);
            Fruit watermelon = new Fruit(getRandomLengthName("Watermelon"), R.drawable.watermelon_pic);
            fruitList.add(watermelon);
            Fruit pear = new Fruit(getRandomLengthName("Pear"), R.drawable.pear_pic);
            fruitList.add(pear);
            Fruit grape = new Fruit(getRandomLengthName("Grape"), R.drawable.grape_pic);
            fruitList.add(grape);
            Fruit pineapple = new Fruit(getRandomLengthName("Pineapple"), R.drawable.pineapple_pic);
            fruitList.add(pineapple);
            Fruit strawberry = new Fruit(getRandomLengthName("Strawberry"), R.drawable.strawberry_pic);
            fruitList.add(strawberry);
            Fruit cherry = new Fruit(getRandomLengthName("Cherry"), R.drawable.cherry_pic);
            fruitList.add(cherry);
            Fruit mango = new Fruit(getRandomLengthName("Mango"), R.drawable.mango_pic);
            fruitList.add(mango);
        }
    }
}
  1. 横向滚动(关键代码)–改布局文件,然后在代码中再设置布局文件的排列方向

layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL)

  1. 瀑布流布局(关键代码)–创建StaggeredGridLayoutManager的实例,在构造函数中传入两个参数,第一个参数用于指定布局的列数,第二个参数用于指定布局的排列方向

StaggeredGridLayoutManager LayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL)

  1. RecyclerView的点击事件
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{

    private List<Fruit> mFruitList;

    static class ViewHolder extends RecyclerView.ViewHolder {
        View fruitView;//添加fruitView变量来保存子项最外层的实例
        ImageView fruitImage;
        TextView fruitName;

        public ViewHolder(View view) {
            super(view);
            fruitView = 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);
        final ViewHolder holder = new ViewHolder(view);//创建ViewHolder的实例
        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();
            }
        });//RecyclerView中TextView的点击事件
        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();
            }
        });//RecyclerView中的ImageView的点击事件
        return holder;
    }

    ......
    ......
}

用RecyclerView编写界面的例子(暂略)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值