<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal|center_vertical"
android:textColor="#00ff00"
android:textSize="24sp"
android:text="This is a TextView!" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false"/>
hint
是用于写入提示用的。maxLines
。2表示输入的内容超过两行时,文本就会向上滚动,EditText则不会再继续拉伸。 <EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"/>
ImageView是用于在界面上展示图片的一个控件。
在res目录下创建一个drawable-xxhdpi目录。放入img【注意这个地方是选择的project而不是app】
app只负责显示,不同文件夹下的创建还是在project下【这也是xlm中的路径】
修改主页布局activity_main.xml
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/apple_pic"/>
动态的修改ImageView中的图片,比如在回调函数中来写(同理java中的代码也是根据app的):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button showEditTextButton = (Button) findViewById(R.id.showEditTextButton);
final EditText editText = (EditText) findViewById(R.id.editText);
ImageView imageView = (ImageView)findViewById(R.id.imageView);
showEditTextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,editText.getText().toString(),Toast.LENGTH_SHORT).show();
imageView.setImageResource(R.drawable.banana_pic);
}
});
}
progressBar用于在界面上显示一个进度条,表示我们的程序正在加载一些数据。它的用法也非常简单,修改activity_main.xml中的代码,如下所示:
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
通过Android:visibility指定控件的可见属性:
切换轮播图效果:
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,editText.getText().toString(),Toast.LENGTH_SHORT).show();
if(progressBar.getVisibility() == View.VISIBLE){
imageView.setImageResource(R.drawable.banana_pic);
progressBar.setVisibility(View.GONE);
}else {
imageView.setImageResource(R.drawable.apple_pic);
progressBar.setVisibility(View.VISIBLE);
}
}
设置横线进度条:
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
把圆的变成横线。android:max="100"
。设置最大值为100progressBar.progress = progressBar.progress +10
TODO:【做成一个每日任务完成进度条 =task_name + expected_comsume_time】
alertDialog可以子啊当前界面弹出一个对话框,这个对话框置顶了。
直接在activity代码中使用即可。
@Override
public void onClick(View v) {
int progress = progressBar.getProgress();
if( progress ==progressBar.getMax()){
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("progressBar is filled, will you want to restart?");
dialog.setCancelable(false);
/**
* 如果Yes就从头开始计算progressBar
*/
dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
progressBar.setProgress(0);
}
});
dialog.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
}else {
progress = progress + 10;
progressBar.setProgress(progress);
}
}
});
线性布局,线性方向上依次排列控件。方向的选择取决于android:orientation
。而控件的对齐方式则是根据android:layout_gravity
relativelayout相对布局,
相对父layout布局:[上对齐+左对齐] [中心对齐]
android:layout_alignParentRight
android:layout_alignParentTop
android:layout_centerInParent
相对于控件对齐:
android:layout_above="@id/button3"
android:layout_toLeftOf="@id/button3"
android:layout_toRightOf="@id/button3"
android:layout_below="@id/button3"
另外一组相对于控件进行定位的属性
android:layout_alignLeft="@id/button3"
表示让一个控件和另外一个控件的左边缘对齐
等等
所有控件都默认在布局的左上角,
这个布局替代了弃用的百分比布局。不过使用relativelayout + linear也够用了。
虽说现在Button已经添加到界面上了,但是由于我们还没有给Button添加任何的约束,因此Button并不知道自己应该出现在什么位置。现在我们在预览界面上看到的Button位置并不是它最终运行后的实际位置,如果一个控件没有添加任何约束的话,它在运行之后会自动位于界面的左上角。
给Button添加约束,每个控件的约束都分为垂直和水平两类,一共可以在四个方向上给控件添加约束:
相对于parent_layout的约束
相对于控件的约束
删除约束的方式一共有三种
Inspector:选中控件右边就会有Properties,其中包括控件的所有属性,如文本内容、颜色、点击事件等等。Properties区域的上半部分,这部分也被称为Inspector
Guidelines:上面的方法很容易时间一个控件的居中,如果我们想让两个按钮共同居中对齐需要用到ConstraintLayout中的一个新的功能,Guidelines。
自动添加约束:TODO
只有linearLayout支持使用layout_weight属性来控制控件的大小
relativeLayout很难实现两个按钮平分布局宽度的效果。
所有的控件都是继承自View的。所有的布局都是继承自ViewGroup的。View是Android中最基本的一种UI组件,它可以在屏幕上绘制一个矩形区域,并能响应这块区域的各种事件。而ViewGroup则是一种特殊的控件,他可以包含很多子view和子viewgroup,是一个用于放置控件和布局的容器。
类似于Vue的组件吧,布局也是可以引入的,A布局引入B布局的方法:
<include layout="@layout/bottom_layout"/>
引入布局可以解决重复编写布局代码的问题。但是布局中有一些控件要求能够响应事件,因此还需要自定义控件
TOOD
ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据会滚动出屏幕。
// private String[] data = {"apple","banana"...}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* android.R.layout. 和 R.layout. 的区别?
*/
ArrayAdapter<String> adapter = new ArrayAdapter<>(MainActivity.this, android.R.layout.simple_expandable_list_item_1, data);
ListView listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(adapter);
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull 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);
TextView fruitText = (TextView) view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitText.setText(fruit.getName());
return view;
}
在mainActivity上面展示出来。
自己创建的包名.R$drawable
获取内部类drawable。然后getField()获取图片的fieldprivate void initFruits(){
for(int i=0;i<data.length;i++) {
String imageName = data[i]+"_pic";
try {
field = Class.forName("com.ssozh.listviewtest.R$drawable").getField(imageName);
Fruit apple = new Fruit(data[i],field.getInt(R.drawable.class));
fruitList.add(apple);
Log.d("initFruits",fruitList.toString());
} catch (NoSuchFieldException | ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
FruitAdapter fruitAdapter = new FruitAdapter(MainActivity.this, R.layout.fruit_item, fruitList);
ListView listView = (ListView)findViewById(R.id.listView);
listView.setAdapter(fruitAdapter);
}
使用getView()方法的参数convertView将之前加载好的布局进行缓存,以便之后可以进行使用。=>不重复加载布局
继续优化=>getView()会调用View的findViewId方法来获取一次控件的实例。=>借助ViewHolder来对这个部分进行优化。
具体就是通过新增一个内部类ViewHolder,用于对控件实例进行缓存。当converView为null的时候,创建一个ViewHolder对象,并将控件的实例都存放在ViewHolder里面,然后调用View的setTag()方法,将ViewHolder对象存储在View中。
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit = getItem(position); // 获取当前项的fruit实例
ViewHolder viewHolder = null;
View view;
if (viewHolder == null) {
view = LayoutInflater.from(getContext())
.inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
view.setTag(viewHolder);
}else {
view = convertView; // converView 就是缓存
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
public ViewHolder(){}
}
和button的点击事件不同,他的点击事件是itemClick而不是直接的clickj同样的,new的View也是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();
}
});
增强版的ListView,不仅可以实现和listView一样的效果,还优化了listview存在的各种不足之处。
写一个RecyclerView的子项:注意Layout占满屏幕可能是因为布局属性没改:https://blog.csdn.net/clzh2013/article/details/53897357
定义一个adapter
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
/**
* 构造函数把Fruit集合传入
*/
public FruitAdapter(List<Fruit> fruitList) {
mFruitList = fruitList;
}
/**
* 创建view 然后创建viewHolder把view放入然后返回。
* 这个方法就类似于ListView的getView
*/
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitName.setText(fruit.fruitName);
holder.fruitImage.setImageResource(fruit.fruitImage);
}
@Override
public int getItemCount() {
return mFruitList.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
ImageView fruitImage;
TextView fruitName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fruitImage = itemView.findViewById(R.id.fruit_image);
fruitName = itemView.findViewById(R.id.fruit_name);
}
@Override
public String toString() {
return super.toString();
}
}
}
在MainActivity中使用recyclerView
fruitList.add(new Fruit(data[i], field.getInt(null)));
Android这个地方可以传入null 暂时还是不是恨透侧。public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
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);
initFruits();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
RecyclerView recyclerView =(RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(linearLayoutManager);
FruitAdapter fruitAdapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(fruitAdapter);
}
private void initFruits(){
for(int i=0;i<data.length;i++) {
String imageName = data[i] + "_pic";
Class clazz = null;
try {
clazz = Class.forName("com.ssozh.recyclerview.R$drawable"); // 注意必须这么写 如果写为com.ssozh.R.drawable这样提示写法是错的反射!!!
Field field = clazz.getField(imageName);
// 通过class.getField返回指定的field域,然后通过fiedl.get(obj)返回obj对象中用Field对象表示的值域。
fruitList.add(new Fruit(data[i], field.getInt(null)));
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
// 重点在这一句!!!
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
RecyclerView recyclerView =(RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(linearLayoutManager);
FruitAdapter fruitAdapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(fruitAdapter);
}
之所以RecyclerView可以横向滚动,是因为RecyclerView将布局排列的任务交给了LayourManager而ListView则是由自身管理的。
RecyclerView提供了GridLayoutManager、StaggerGridLayoutManager和LinearLayoutManager三种内置的布局排泄方法。
RecyclerView没有提供类似于setOnItemClickListener)这样的注册监听器的方法,而是需要我们自己给子项具体的view去注册点击事件。
之所以这么做,是因为recyclerview可以给子项中具体的某一个按钮(view)去注册。
=>具体实现是修改fruitAdapter中的代码:
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
// 点击事件写在这里
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = viewHolder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"you click view" + fruit.getFruitName(),Toast.LENGTH_SHORT).show();
}
});
viewHolder.fruitImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = viewHolder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"you click view" + fruit.getFruitName(),Toast.LENGTH_SHORT).show();
}
});
return viewHolder;
}
9-patch图片是一种经过特殊处理过的png图片,能够制定哪些区域可以被拉伸、哪些区域不可以。在Android studio中,我们可以将任何png类型的图片制作成9-patch图片。
在主界面放一个recyclerView用于显示聊天的消息内容,又放置了一个editText用于输入信息,一个button用于发送消息。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/msg_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="type something here"
android:maxLines="2"/>
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send"/>
</LinearLayout>
编写RecyclerVew的子项布局msg_item.xml【LinearLayout】(第三版书包括发送消息的子布局msg_left_item.xml和接收消息的子布局msg_right_item.xml)
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:background="@drawable/message_left">
<TextView
android:id="@+id/left_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#fff"/>
</LinearLayout>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:background="@drawable/message_right">
<TextView
android:id="@+id/right_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#000"/>
</LinearLayout>
定义消息实体类,新建Msg
public final static int TYPE_RECEIVED = 0;
public final static int TYPE_SEND = 1;
private String content;
private int type;
编写上面消息类实体的MsgAdapter:
定义静态内部类ViewHolder包括:左右消息子布局【linearLayout】和两个TextView
LinearLayout leftLayout;
LinearLayout rightLayout;
TextView leftMsg;
TextView rightMsg;
public ViewHolder(@NonNull View itemView) {
super(itemView);
leftLayout = (LinearLayout) itemView.findViewById(R.id.left_layout);
leftMsg = (TextView) itemView.findViewById(R.id.left_msg);
rightLayout =(LinearLayout) itemView.findViewById(R.id.right_layout);
rightMsg = (TextView)itemView.findViewById(R.id.right_msg);
}
构造函数应该把msg集合内容传入MsgAdapter:
private List<Msg> mMsgList;
public MsgAdapter(List<Msg> msgList) {
this.mMsgList = msgList;
}
继承RecyclerView.Adapter<MsgAdapter.ViewHolder>
类必须重写的两个方法:
onCreateViewHolder
用来创建ViewHolder实例。
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.msg_item,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
onBindViewHolder
:用来对RecyclerView子项的数据进行赋值,会在每个子项被滚动到屏幕内的时候执行
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Msg msg = mMsgList.get(position);
if(msg.getType() == Msg.TYPE_RECEIVED){
// 表名是接受消息,显示左边,隐藏右边
holder.leftLayout.setVisibility(View.VISIBLE);
holder.rightLayout.setVisibility(View.GONE);
holder.leftMsg.setText(msg.getContent());
return;
}
if(msg.getType() == Msg.TYPE_SEND){
// 表名是接受消息,显示左边,隐藏右边
holder.leftLayout.setVisibility(View.GONE);
holder.rightLayout.setVisibility(View.VISIBLE);
holder.rightMsg.setText(msg.getContent());
}
}
最后在mainActivity上写相关逻辑:
初始化msg集合,也就是历史聊天记录
public void initMsgs(){
Msg msg1 = new Msg("hello ssozh", Msg.TYPE_RECEIVED);
msgList.add(msg1);
Msg msg2 = new Msg("hello,Who is that", Msg.TYPE_SEND);
msgList.add(msg2);
Msg msg3 = new Msg("This is Tom. Nice to meet you ", Msg.TYPE_RECEIVED);
msgList.add(msg3);
}
获取发送button、输入文本框inputText以及msgRecyclerView这几个view
【重点】创建layoutManager 并绑定msgRecyclerView=>否则报错E/RecyclerView: No layout manager attached; skipping layout
创建adpater并绑定
编写send按钮的回调函数
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMsgs();
inputText = (EditText) findViewById(R.id.input_text);
send = (Button) findViewById(R.id.send);
msgRecyclerView = (RecyclerView) findViewById(R.id.msg_recycler_view);
// 重点:E/RecyclerView: No layout manager attached; skipping layout
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
msgRecyclerView.setLayoutManager(layoutManager);
adapter = new MsgAdapter(msgList);
msgRecyclerView.setAdapter(adapter);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = inputText.getText().toString();
if(!"".equals( content)){
Msg msg = new Msg(content,Msg.TYPE_SEND);
msgList.add(msg);
// 当有新消息的时候刷新ListView定位到最后一行
adapter.notifyItemChanged(msgList.size()-1);
// 清空输入框
inputText.setText("");
}
}
});
}
原文:https://www.cnblogs.com/SsoZhNO-1/p/14012552.html