activity_main.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/main_layout"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
MainActivity
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private TabLayout mTabLayout;
private List<Fragment> fragmentList;
private List<String> tabList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mTabLayout = (TabLayout) findViewById(R.id.tab_layout);
initTitle(); //添加Tab
initFragment();// 添加Fragment
mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
@NonNull
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return tabList.get(position);
}
});
mTabLayout.setupWithViewPager(mViewPager);
}
private void initFragment(){
fragmentList = new ArrayList<>();
fragmentList.add(new BlankFragment1());
fragmentList.add(new BlankFragment2());
fragmentList.add(new BlankFragment3());
}
private void initTitle(){
tabList = new ArrayList<>();
tabList.add("haha");
tabList.add("lala");
tabList.add("fafa");
}
}
自定义LinerLayout
重写onFinishInflate() 和onVisibilityChanged()
public class TimeView extends LinearLayout {
private TextView timeText;
// 少构造方法,会报错
public TimeView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public TimeView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public TimeView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
//当XML布局文件被布局加载完,所有子控件均被映射之后,才会回调这个方法
@Override
protected void onFinishInflate() {
// TODO Auto-generated method stub
super.onFinishInflate();
timeText = (TextView) findViewById(R.id.text_view1);
timeHandler.sendEmptyMessage(0);
}
private void refreshTime() {
Calendar cal = Calendar.getInstance();
String timeStr = String.format("%d:%d:%d", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND));
timeText.setText(timeStr);
//System.out.println("timeStr============>" + timeStr);
}
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
// TODO Auto-generated method stub
super.onVisibilityChanged(changedView, visibility);
//对view的可见性进行判断
if (getVisibility() == View.VISIBLE) {
timeHandler.sendEmptyMessageDelayed(0, 1000);
} else {
timeHandler.removeMessages(0);
}
}
private Handler timeHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
refreshTime();
if (getVisibility() == View.VISIBLE) {
// 每隔一秒给自己发送消息
timeHandler.sendEmptyMessageDelayed(0, 1000);
}
};
};
}
将自定义的LinerLayout添加到fragment的xml中,实现了一个fragment的时钟功能。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment"
tools:context=".BlankFragment1">
<!-- TODO: Update blank fragment layout -->
<com.thundersoft.tablayout.TimeView
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/text_view1"
android:textSize="80sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</com.thundersoft.tablayout.TimeView>
</FrameLayout>
View的生命周期方法
View的生命周期从构造方法开始依次执行以下几个方法,该View的可见性为默认值时:
(0)Constructors()
View在代码中被创建时调用第一种构造方法,View从layout中加载出来时会被调用第二种构造方法,其中XML中的属性也会被解析。
(1)onFinishInflate()
该方法当View及其子View从XML文件中加载完成后触发调用。通常是在Activity中的onCreate方法调用后调用。
(2)onVisibilityChanged()
该方法在当前View或其祖先的可见性改变时被调用。如果View状态不可见或者GONE,该方法会第一个被调用。
(3)onAttachedToWindow()
当View被附着到一个窗口时触发。在Activity第一次执行完onResume方法后被调用。
(4)onMeasure()
该方法确定View以及其子View尺寸大小时被调用。
(5)onSizeChanged()
该方法在Measure方法之后且测量大小与之前不一样的时候被调用。
(6)onLayout()
该方法在当前View需要为其子View分配尺寸和位置时会被调用。
(7)onDraw(Canvas)
该方法用于View渲染内容的细节。
(8)onWindowFocusChanged()
该方法也可能在绘制过程中被调用,具体是在包含当前View的Window获得或失去焦点时被调用。此时可以设置代码中定义的View的一些LayoutParameter。
如果View进入了销毁阶段,肯定是会被调用的。
(9)onWindowVisibilityChanged()
该方法同上,具体是在包含当前View的Window可见性改变时被调用。
(10)onDetachedFromWindow()
当View离开附着的窗口时触发,比如在Activity调用onDestroy方法时View就会离开窗口。和一开始的AttachedToWindow相对,都只会被调用一次。
因此可以总结为:
(1)在Activity的onCreate方法中加载View,View的onFinishInflate会被调用,继而Activity的生命周期执行到onResume方法之后View才被附着到窗口上,继而进行绘制工作,onMeasure、onSizeChanged 、onLayout、onDraw。这几个方法可能由于setVisible或onResume被调用多次,最后是Window失去焦点后的销毁阶段。
(2)onVisibilityChanged()方法在View是可见状态时如上所示时机调用,但是View的状态如果是不可见或者GONE时,是首先被调用的。如果是Invisible状态,View的创建到layout即结束,不会绘制出来。如果是GONE状态,View也会被加载并添加到Window,但是不会再Measure、Layout和Draw了。也就时说即使是GONE状态,销毁时一样有Detach的过程,即View的销毁过程和可见性无关。