(1)开发一个单页面的APP。
(2)“线性布局”TAB页:显示个人相关信息,需要使用TextView、EditText、Button、CheckBox等控件。(页面内容也可自行设计)
(3)“触摸屏处理”TAB页:在规定区域内实现触摸屏功能。
(4)其他TAB页:可自行设计页面功能。
1、工程创建
file->new->new project->Tabbed Activity
2、观察里面的工程内容,会发现里面有几个需要我们注意的东西。
我们知道Tab页面可以分出好几个,而老师或者一些很老的博客里面会告诉我们,若是我们需要n个Tab页面,我们则需要在一个project中新建n个fragmentactivity的Java文件和xml文件。
但是在这个project里面我们只看到了一个fragment.xml文件,而在运行模拟器时却发现有两个Tab。
3、这时返回去看代码,在ui.main文件夹下我们找到了一个名为SectionsPagerAdapter的Java文件。
这个文件很重要,因为其内包含了Tab的标题、Tab的内容等代码,这也恰恰表明,此次制作Tab的主角就是SectionsPagerAdapter.java。
但是在对它“动手”之前,请先在布局文件中新建两个布局文件。在这里,用红框框的第一个文件是我的第一个Tab,第二个文件是第二个Tab。
拿来主义,上课时录了个视频,把老师在PPT上展示的代码直接敲下来用了,所以第一个xml文件用的还是老师上课展示的代码。
第二个xml文件里用的是书上的代码。
因为不是这次的重点,这里就不放了,主要用到的还是布局嵌套,按键用的是RadioButton。
4、开始看主角文件里的代码。
直接用它封装好的工程的好处就是有的地方有注释,还能省许多心。
从上图的注释中,我们可以知道这个名字叫FragmentPagerAdapter的东西(类)可以返回与某个部分/分栏/页对应的片段。
这里的Tab有两个,用了个数组(也许?)来定义它们,我改了改名字。
改名字可以在上面图片的数组里面改,如果会报错的话,也可以在res->values->string.xml修改相应的Tab名字,因为这里Tab的标题名字就是源自于string.xml文件里的,代码参数为:new int[]{R.layout.Tab1,R.layout.Tab2}。
而这个getItem则是定位用的(如果我没猜错的话),它可以根据Tab不同位置呈现不同的内容。
所以等会需要在这里修改返回内容。
后面还有两段代码不是我们重点要关注的地方,可以暂时不用管(如果不需要自行车的话)。
5、在这里,我们利用getItem去获取我们要显示的页面。把return后返回的内容删掉,用switch去返回我们需要的页面,页面内容在Tab1和Tab2里。
@Override
//根据tab不同位置呈现不同的内容
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
public Fragment getItem(int position) {
switch (position){
case 0:
return new Tab1();
case 1:
return new Tab2();
}
return null;
}
然后建立一个静态类页面,其父类是Fragment。
public static class Tab1 extends Fragment
{
//内容
}
接下来就可以往这个类里放我们要的东西了,在这里写下的代码是直接用于页面上的。
在这里我直接挪用了老师的代码。
public static class Tab1 extends Fragment {
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View v = inflater.inflate(R.layout.section_pager_adapter, container, false);
final RadioButton rb1 = (RadioButton) v.findViewById(R.id.RadioButton1);
final RadioButton rb2 = (RadioButton) v.findViewById(R.id.RadioButton2);
final EditText ed1 = (EditText) v.findViewById(R.id.entry1);
final EditText ed2 = (EditText) v.findViewById(R.id.entry2);
final TextView text1 = (TextView) v.findViewById(R.id.label4);
Button but1 = (Button) v.findViewById(R.id.get);
Button but2 = (Button) v.findViewById(R.id.cancel);
final String str3="";
but1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String str1 = ed1.getText().toString();
String str2 = ed2.getText().toString();
String str3 = null;
if(rb1.isChecked())
str3=rb1.getText().toString();
if(rb2.isChecked())
str3=rb2.getText().toString();
text1.setText("姓名:"+str1+" 年龄:"+str2+" 是否现在睡觉:"+str3);
}
});
but2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ed1.setText("");
ed2.setText("");
rb1.setChecked(false);
rb2.setChecked(false);
}
});
return v;
}
}
在这里实例化的两个button是用来作“获取”和“清除”作用的,代码内容和我上一篇上机的博客差不多,在此不做赘述。
重点是这行代码。
View v = inflater.inflate(R.layout.section_pager_adapter, container, false);
然后照着Tab1的样子建立一个Tab2。这里的Tab2页面内容是书上的一个触摸事件(touch event)。
需要用到MotionEvent的包,重写里也要像Tab1一样加上LayoutInflater和ViewGroup容器,还有重写方法… …代码不难,花两分钟多看两眼基本能知道是什么了。
public static class Tab2 extends Fragment{
@SuppressLint("ClickableViewAccessibility")
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
TextView labelView = null;
View v = inflater.inflate(R.layout.touch_event, container, false);
labelView = (TextView) v.findViewById(R.id.event_label);
TextView touchView = (TextView)v.findViewById(R.id.touch_area);
final TextView historyView = (TextView)v.findViewById(R.id.history_label);
TextView finalLabelView = labelView;
touchView.setOnTouchListener(new View.OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case (MotionEvent.ACTION_DOWN):
Display("ACTION_DOWN",event);
break;
case (MotionEvent.ACTION_UP):
int historySize = ProcessHistory(event);
historyView.setText("历史数据量:"+historySize);
Display("ACTION_UP",event);
break;
case (MotionEvent.ACTION_MOVE):
Display("ACTION_MOVE",event);
break;
}
return true;
}
private void Display(String eventType, MotionEvent event){
int x = (int)event.getX();
int y = (int)event.getY();
float pressure = event.getPressure();
float size = event.getSize();
int RawX = (int)event.getRawX();
int RawY = (int)event.getRawY();
String msg = "";
msg += "事件类型:" + eventType + "\n";
msg += "相对坐标:"+String.valueOf(x)+","+String.valueOf(y)+"\n";
msg += "绝对坐标:"+String.valueOf(RawX)+","+String.valueOf(RawY)+"\n";
msg += "触点压力:"+String.valueOf(pressure)+", ";
msg += "触点尺寸:"+String.valueOf(size)+"\n";
finalLabelView.setText(msg);
}
private int ProcessHistory(MotionEvent event)
{
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
long time = event.getHistoricalEventTime(i);
float pressure = event.getHistoricalPressure(i);
float x = event.getHistoricalX(i);
float y = event.getHistoricalY(i);
float size = event.getHistoricalSize(i);
}
return historySize;
}
});
return v;
}
}
其实在一开始的时候我的代码会显示出高亮的一块黄色,像下面这样。
很迷茫,在网上找了也只有一个答案“代码写得不规范导致”,但是怎么改呢?完全没有解决方案,虽然也能够运行,但是看着很难受… …
后来当我因为另一个problem一筹莫展的时候,不小心点到了页面的某个地方,它给我自动添加了一行代码,我的代码终于恢复正常了。
添加了这行代码:
@SuppressLint("ClickableViewAccessibility")
后来去网上找了才知道是什么问题,在文章结尾会附上相关链接。
在一开始运行模拟器的时候发现页面右下角有一个悬浮窗口,点击其窗口会出现弹窗文字。
其监听器在MainActivity.java文件中,因为只是了解,并没有过多深究,所以只是改了其文本内容。
但是这个文件里的内容很重要,因为其控制了我们整个工程的页面。
注:因为是在模拟器上跑的代码,用的是鼠标点击“屏幕”,所以这里的触点压力和触点尺寸分别恒为1.0和0.0。
只能说,这次的上机很坎坷,因为在一开始,是想要按部就班地抄书上的代码,然后就好了,但是没想到书上的代码有的函数在AndroidStudio里已经失效了,运行时工程直接闪退,于是开始去网上找方法看看能不能改用别的方法去运行这个工程,但是没想到,这一找,就踏上了Android开发的坎坷之路。
结果跳转到官网的另外一个页面,它叫我用navigation… …我不死心,我就去网上找例程,找之前在图书馆借的书里的随书代码… …
跑了几个很炫酷的例程,但我仍然对Fragment这个东西一无所知。
而就在10月5日,也就是三天前,我闲得无聊,新建工程的时候发现在工程样式最下面有一个名为“Tabbed Activity”的样式。
喜出望外,遂新建工程。
毫无进展,因为看不懂代码,怎么没有fragmenta、fragmentb就能够创建出两个页面了?怎么这个MainActivity里面什么东西也没有?
然后又是漫长地寻找代码含义的道路。
终于,我在我的收藏夹里找到一个极具关键性的博客。是的,这篇博客给我接下来的代码提供了关键。
我终于知道Fragment是什么了!原来在Android升级之后,Fragment被改变成了一个类,但是因为不是Activity这样的类,所以我们不能直接使用findViewbyId去寻找我们布局文件里的控件,而需要构造一个LayoutInflater方法去构建一个view,虽然这个老师在上课也讲过,但是当时的我懵懵懂懂,而且第二天就是国庆了,我的心早已经放假了。
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
而在继承Fragment父类时,要先导入以上类。
然后就开始啃代码,写代码了。
这次的上机2我用了6天的时间终于写完,而这篇博客,我花了两天的时间写完,其中的苦难不言而喻。
以下这些链接是我在这次上机内容中参考过的网站或博客。
ActionBar
Navigation Editor
Android架构组件-Navigation的使用(一)
Tabbed Activity的使用(Fragment)
使用 ViewPager2 创建包含标签的滑动视图
Navigation导航图
Android Studio开发学习(十三)——Fragment
android studio有时写着代码,突然某一块代码背景变成土黄色
响应触摸事件
在安卓开发中,我需要将AppCompatActivity 转换fragment,请问该如何更改
Issue id: ClickableViewAccessibility
【Android】inflater的作用
使用TAB和新的工具栏(APPCOMPAT V7-21)
navigation/Menu1Fragment.kt