Android 仿微信底部渐变Tab效果

先来看一下效果图

除了第三个的发现Tab有所差别外,其他的基本还原了微信的底部Tab渐变效果

每个Tab都是一个自定义View,根据ImageView的tint属性来实现颜色渐变效果,tint属性的使用可以看我的上一篇文章

我将自定义View命名为ShadeView,包含四个自定义属性

意思分别为图标、背景色、底部文本、底部文本大小

  <declare-styleable name="ShadeView">
    <attr name="icon" format="reference" />
    <attr name="color" format="color" />
    <attr name="text" format="string" />
    <attr name="text_size" format="dimension" />
  </declare-styleable>

ShadeView的定义如下,主要是进行绘图操作,并向外提供改变透明度和图标的方法

public class ShadeView extends View {
  /**
   * 图标
   */
  private Bitmap iconBitmap;
  /**
   * 图标背景色
   */
  private int iconBackgroundColor;
  /**
   * 图标默认背景色
   */
  private final int DEFAULT_ICON_BACKGROUND_COLOR = 0x3CAF36;
  /**
   * 图标底部文本
   */
  private String text;
  /**
   * 图标底部文字默认大小(sp)
   */
  private final int DEFAULT_TEXT_SIZE = 12;
  /**
   * 图标底部文字默认颜色
   */
  private final int DEFAULT_TEXT_COLOR = 0x2B2B2B;
  /**
   * 图标绘制范围
   */
  private Rect iconRect;
  /**
   * 文字笔画
   */
  private Paint textPaint;
  /**
   * 文字范围
   */
  private Rect textBound;
  /**
   * 透明度(0.0-1.0)
   */
  private float mAlpha;
  private Bitmap mBitmap;
  public ShadeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    //获取自定义属性值
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShadeView);
    BitmapDrawable drawable = (BitmapDrawable) typedArray.getDrawable(R.styleable.ShadeView_icon);
    if (drawable != null) {
      iconBitmap = drawable.getBitmap();
    }
    iconBackgroundColor = typedArray.getColor(R.styleable.ShadeView_color, DEFAULT_ICON_BACKGROUND_COLOR);
    text = typedArray.getString(R.styleable.ShadeView_text);
    int textSize = (int) typedArray.getDimension(R.styleable.ShadeView_text_size,
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, DEFAULT_TEXT_SIZE, getResources().getDisplayMetrics()));
    //资源回收
    typedArray.recycle();
    //初始化
    textBound = new Rect();
    textPaint = new Paint();
    textPaint.setTextSize(textSize);
    textPaint.setColor(DEFAULT_TEXT_COLOR);
    textPaint.setAntiAlias(true);
    textPaint.setDither(true);
    textPaint.getTextBounds(text, 0, text.length(), textBound);
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //因为图标是正方形且需要居中显示的,所以View的大小去掉padding和文字所占空间后,
    //剩余的空间的宽和高的最小值才是图标的边长
    int bitmapSide = Math.min(getMeasuredWidth() - getPaddingLeft()
        - getPaddingRight(), getMeasuredHeight() - getPaddingTop()
        - getPaddingBottom() - textBound.height());
    int left = getMeasuredWidth() / 2 - bitmapSide / 2;
    int top = (getMeasuredHeight() - textBound.height()) / 2 - bitmapSide / 2;
    //获取图标的绘制范围
    iconRect = new Rect(left, top, left + bitmapSide, top + bitmapSide);
  }
  @Override
  protected void onDraw(Canvas canvas) {
    //进一取整
    int alpha = (int) Math.ceil((255 * mAlpha));
    //绘制原图标
    canvas.drawBitmap(iconBitmap, null, iconRect, null);
    setupTargetBitmap(alpha);
    drawSourceText(canvas, alpha);
    drawTargetText(canvas, alpha);
    canvas.drawBitmap(mBitmap, 0, 0, null);
  }
  /**
   * 在mBitmap上绘制以iconBackgroundColor颜色为Dst,DST_IN模式下的图标
   *
   * @param alpha Src颜色的透明度
   */
  private void setupTargetBitmap(int alpha) {
    mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Config.ARGB_8888);
    Canvas canvas = new Canvas(mBitmap);
    Paint paint = new Paint();
    paint.setColor(iconBackgroundColor);
    paint.setAntiAlias(true);
    paint.setDither(true);
    paint.setAlpha(alpha);
    //在图标背后先绘制一层iconBackgroundColor颜色的背景
    canvas.drawRect(iconRect, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    paint.setAlpha(255);
    //在mBitmap上绘制以iconBackgroundColor颜色为Dst,DST_IN模式下的图标
    canvas.drawBitmap(iconBitmap, null, iconRect, paint);
  }
  /**
   * 绘制默认状态下的字体
   *
   * @param canvas Canvas
   * @param alpha 字体颜色透明度
   */
  private void drawSourceText(Canvas canvas, int alpha) {
    textPaint.setColor(DEFAULT_TEXT_COLOR);
    textPaint.setAlpha(255 - alpha);
    canvas.drawText(text, iconRect.left + iconRect.width() / 2 - textBound.width() / 2,
        iconRect.bottom + textBound.height(), textPaint);
  }
  /**
   * 绘制滑动到该标签时的字体
   *
   * @param canvas Canvas
   * @param alpha 字体颜色透明度
   */
  private void drawTargetText(Canvas canvas, int alpha) {
    textPaint.setColor(iconBackgroundColor);
    textPaint.setAlpha(alpha);
    canvas.drawText(text, iconRect.left + iconRect.width() / 2 - textBound.width() / 2,
        iconRect.bottom + textBound.height(), textPaint);
  }
  /**
   * 设置图标透明度并重绘
   *
   * @param alpha 透明度
   */
  public void setIconAlpha(float alpha) {
    if (mAlpha != alpha) {
      this.mAlpha = alpha;
      invalidateView();
    }
  }
  public void setIconBitmap(Context context, int resourceID) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) ContextCompat.getDrawable(context, resourceID);
    if (!bitmapDrawable.getBitmap().equals(iconBitmap)) {
      iconBitmap = bitmapDrawable.getBitmap();
      invalidateView();
    }
  }
  /**
   * 判断当前是否为UI线程,是则直接重绘,否则调用postInvalidate()利用Handler来重绘
   */
  private void invalidateView() {
    if (Looper.getMainLooper() == Looper.myLooper()) {
      invalidate();
    } else {
      postInvalidate();
    }
  }
  private static final String STATE_INSTANCE = "STATE_INSTANCE";
  private static final String STATE_ALPHA = "STATE_ALPHA";
  /**
   * 保存状态
   *
   * @return Parcelable
   */
  @Override
  protected Parcelable onSaveInstanceState() {
    Bundle bundle = new Bundle();
    bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
    bundle.putFloat(STATE_ALPHA, mAlpha);
    return bundle;
  }
  /**
   * 恢复状态
   *
   * @param parcelable Parcelable
   */
  @Override
  protected void onRestoreInstanceState(Parcelable parcelable) {
    if (parcelable instanceof Bundle) {
      Bundle bundle = (Bundle) parcelable;
      mAlpha = bundle.getFloat(STATE_ALPHA);
      super.onRestoreInstanceState(bundle.getParcelable(STATE_INSTANCE));
    } else {
      super.onRestoreInstanceState(parcelable);
    }
  }
}

然后在布局文件中声明使用,这里不需要每个自定义属性都使用到,因为我也提供了默认值

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">
  <android.support.v4.view.ViewPager
    android:id="@+id/id_viewpager"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />
  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="@drawable/tab_background"
    android:orientation="horizontal"
    android:paddingBottom="3dp"
    android:paddingTop="1dp">
    <com.example.zy.myapplication.ShadeView
      android:id="@+id/id_indicator_one"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      app:icon="@drawable/weixin"
      app:text="微信" />
    <com.example.zy.myapplication.ShadeView
      android:id="@+id/id_indicator_two"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      app:icon="@drawable/address_book"
      app:text="通讯录" />
    <com.example.zy.myapplication.ShadeView
      android:id="@+id/id_indicator_three"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      app:icon="@drawable/discover"
      app:text="发现" />
    <com.example.zy.myapplication.ShadeView
      android:id="@+id/id_indicator_four"
      android:layout_width="0dp"
      android:layout_height="match_parent"
      android:layout_weight="1"
      android:padding="5dp"
      app:icon="@drawable/me"
      app:text="我" />
  </LinearLayout>
</LinearLayout>

因为主界面是ViewPager,这里就需要一个Fragment子类

public class TabFragment extends Fragment {
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    String mTitle = "微信";
    if (getArguments() != null) {
      mTitle = getArguments().getString("Title", "微信");
    }
    TextView textView = new TextView(getActivity());
    textView.setTextSize(25);
    textView.setGravity(Gravity.CENTER);
    textView.setText(mTitle);
    return textView;
  }
}

MainActivity代码如下,重点是对viewPager进行滑动监听,根据滑动偏移量来动态改变透明度alpha,从而实现颜色渐变效果

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, View.OnClickListener {
  private List<TabFragment> tabFragments;
  private List<ShadeView> tabIndicators;
  private ViewPager viewPager;
  private FragmentPagerAdapter adapter;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initData();
    viewPager = (ViewPager) findViewById(R.id.id_viewpager);
    viewPager.setAdapter(adapter);
    viewPager.addOnPageChangeListener(this);
  }
  private void initData() {
    tabFragments = new ArrayList<>();
    tabIndicators = new ArrayList<>();
    String[] titles = new String[]{"微信", "通讯录", "发现", "我"};
    for (String title : titles) {
      TabFragment tabFragment = new TabFragment();
      Bundle bundle = new Bundle();
      bundle.putString("Title", title);
      tabFragment.setArguments(bundle);
      tabFragments.add(tabFragment);
    }
    adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
      @Override
      public int getCount() {
        return tabFragments.size();
      }
      @Override
      public Fragment getItem(int arg0) {
        return tabFragments.get(arg0);
      }
    };
    initTabIndicator();
  }
  private void initTabIndicator() {
    ShadeView one = (ShadeView) findViewById(R.id.id_indicator_one);
    ShadeView two = (ShadeView) findViewById(R.id.id_indicator_two);
    ShadeView three = (ShadeView) findViewById(R.id.id_indicator_three);
    ShadeView four = (ShadeView) findViewById(R.id.id_indicator_four);
    tabIndicators.add(one);
    tabIndicators.add(two);
    tabIndicators.add(three);
    tabIndicators.add(four);
    one.setOnClickListener(this);
    two.setOnClickListener(this);
    three.setOnClickListener(this);
    four.setOnClickListener(this);
    one.setIconAlpha(1.0f);
  }
  @Override
  public void onClick(View v) {
    resetTabsStatus();
    switch (v.getId()) {
      case R.id.id_indicator_one:
        tabIndicators.get(0).setIconAlpha(1.0f);
        viewPager.setCurrentItem(0, false);
        break;
      case R.id.id_indicator_two:
        tabIndicators.get(1).setIconAlpha(1.0f);
        viewPager.setCurrentItem(1, false);
        break;
      case R.id.id_indicator_three:
        tabIndicators.get(2).setIconAlpha(1.0f);
        viewPager.setCurrentItem(2, false);
        break;
      case R.id.id_indicator_four:
        tabIndicators.get(3).setIconAlpha(1.0f);
        viewPager.setCurrentItem(3, false);
        break;
    }
  }
  /**
   * 重置Tab状态
   */
  private void resetTabsStatus() {
    for (int i = 0; i < tabIndicators.size(); i++) {
      tabIndicators.get(i).setIconAlpha(0);
    }
  }
  /**
   * 如果是直接点击图标来跳转页面的话,position值为0到3,positionOffset一直为0.0
   * 如果是通过滑动来跳转页面的话
   * 假如是从第一页滑动到第二页
   * 在这个过程中,positionOffset从接近0逐渐增大到接近1.0,滑动完成后又恢复到0.0,而position只有在滑动完成后才从0变为1
   * 假如是从第二页滑动到第一页
   * 在这个过程中,positionOffset从接近1.0逐渐减小到0.0,而position一直是0
   *
   * @param position       当前页面索引
   * @param positionOffset    偏移量
   * @param positionOffsetPixels 偏移量
   */
  @Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    Log.e("TAG", "position==" + position);
    Log.e("TAG", "positionOffset==" + positionOffset);
    Log.e("TAG", "positionOffsetPixels==" + positionOffsetPixels);
    if (positionOffset > 0) {
      ShadeView leftTab = tabIndicators.get(position);
      ShadeView rightTab = tabIndicators.get(position + 1);
      leftTab.setIconAlpha(1 - positionOffset);
      rightTab.setIconAlpha(positionOffset);
    }
  }
  @Override
  public void onPageSelected(int position) {
    if (position == 2) {
      tabIndicators.get(position).setIconBitmap(this, R.drawable.discover_green);
    } else {
      tabIndicators.get(2).setIconBitmap(this, R.drawable.discover);
    }
  }
  @Override
  public void onPageScrollStateChanged(int state) {
  }
}

总结

以上所述是小编给大家介绍的Android 仿微信底部渐变Tab效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

您可能感兴趣的文章:

  • Android 使用FragmentTabHost实现底部菜单功能
  • Android中修改TabLayout底部导航条Indicator长短的方法
  • Android TabWidget底部显示效果
  • Android编程实现将tab选项卡放在屏幕底部的方法
  • Android中TabLayout+ViewPager 简单实现app底部Tab导航栏
  • Android design包自定义tablayout的底部导航栏的实现方法
  • 关注Ionic底部导航按钮tabs在android情况下浮在上面的处理
  • Android仿微信底部实现Tab选项卡切换效果
  • android 选项卡(TabHost)如何放置在屏幕的底部
  • Android TabLayout 实现底部Tab的示例代码
时间: 2017-12-26

android 选项卡(TabHost)如何放置在屏幕的底部

今天写Tab的时候由于TAB的跳转问题去查资料,倒反而发现更有趣的问题,就是如何将TAB放置在屏幕的底端. 复制代码 代码如下: <?xml version="1.0" encoding="utf-8"?> <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" a

Android中修改TabLayout底部导航条Indicator长短的方法

前言 对于Tablayout相信大家都不陌生,在开发中使用的应该很频繁了,但是底部导航条长短是固定死的,需要自己来改动长短,找了半天没找着方法,看了下官方建议,可以通过映射来修改自己想要的长短,其实也就几行代码的问题. 看代码: public static void setIndicator(Context context, TabLayout tabs, int leftDip, int rightDip) { Class<?> tabLayout = tabs.getClass(); Fi

关注Ionic底部导航按钮tabs在android情况下浮在上面的处理

Ionic是一款流行的移动端开发框架,但是刚入门的同学会发现,Ionic在iOS和Android的底部tabs显示不一样.在安卓情况下底部tabs会浮上去. 如下图展示: 网上也有很多此类的解决方案,但是我觉得说一千道一万都不如给个dome实在,下面附上解决方案的dome,大家可以看看! <!DOCTYPE html> <html ng-app="ionic"> <head> <meta charset="UTF-8">

Android design包自定义tablayout的底部导航栏的实现方法

以前做项目大多用的radiobutton,今天用tablayout来做一个tab切换页面的的效果. 实现的效果就是类似QQ.微信的页面间(也就是Fragment间)的切换.如图: 布局只要一个tablayout <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id=&

Android中TabLayout+ViewPager 简单实现app底部Tab导航栏

前言 在谷歌发布Android Design Support Library之前,app底部tab布局的实现方法就有很多种,其中有RadioGroup+FrameLayout.TabHost+Fragment.FragmentPagerAdapter+ViewPager等方法,虽然这些方法虽然能达到同样的效果,但我个人总觉得有些繁琐.然而,Google在2015的IO大会上,给开发者们带来了全新的Android Design Support Library,里面包含了许多新控件,这些新控件有许多

Android 使用FragmentTabHost实现底部菜单功能

前言 现在大部分App底部都有一个菜单,实现这个功能也有好多办法: - TabHost+Fragment - RadioGroup+Fragment - FragmentTabHost+Fragment - 5.0以后有个新控件,BottomNavigator 这篇主要介绍下FragmentTabHost配合Fragment使用 运行效果图 效果图分析 FragmentTabHost简单介绍 首先我们看下官方文档的介绍 OK,接着官方还给出了一份使用的代码,我们也来看下 Activity中使用

Android编程实现将tab选项卡放在屏幕底部的方法

本文实例讲述了Android编程实现将tab选项卡放在屏幕底部的方法.分享给大家供大家参考,具体如下: 今天写Tab的时候由于TAB的跳转问题去查资料,倒反而发现更有趣的问题,就是如何将TAB放置在屏幕的底端.有点类似IPhone里的布局了,呵呵-(其实后来发现这个应该不是用TAB做的,而是ButtonBar做出来的吧,或者是他重写了TAB?总之不是简单地将TAB放置底端了). 要放置底端,那么Android自带的例程是不可以做到的(例程参看development-ApiDemo).先需要写一个

Android TabWidget底部显示效果

TabHost控件默认使用LinearLayout包裹TabWidget和FrameLayout,布局文件如下: <TabHost xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="

Android仿微信底部实现Tab选项卡切换效果

在网上看了比较多的关于Tab的教程,发现都很杂乱.比较多的用法是用TitlePagerTabStrip和ViewPaper.不过TitlePagerTabStrip有个很大的缺陷,Tab里面的内容刚进去是没有的,要滑一次才能加载出来.而且滑动的时候,Tab里面的内容位置不是固定的,滑倒最后会出现一片空白,非常不美观.虽然有其他的补救方法,但是非常的麻烦,所以我就按照自己的方法实现了一个,功能不错而且非常简单. 直接点击或者是滑动界面,都可以转到相应的页面. 效果图: 原理是用了三个按钮和View

Android TabLayout 实现底部Tab的示例代码

前言 底部Tab已经是一个应用的标配了,因为手机屏幕大小的限制,使得我们必须去最大化的利用可见的空间.当然底部Tab一般为3个左右,最多不会超过5个. 效果图 下面是我使用TabLayout来实现的底部Tab, 实现方式也很简单,因为这里没有"小滑块".只需要去处理,Tab的滑动和点击即可. 代码: public class CustomBotTabItem { private TabLayout mTabLayout; private ViewPager mViewPager; pr

Android中TabLayout添加小红点的示例代码

本文介绍了Android中TabLayout添加小红点的示例代码,分享给大家,具体如下 安卓原生的android.support.design.widget.TabLayout,配合ViewPager已经很好用了,但是有时我们会在内容更新时,在tab标题右上方加上一个红点等标记此tab内容有更新时,就需要给原生的TabLayout设置你定义的布局,用法和原生的一样,只是在代码中设置一下TabLayout的布局. 1.主布局文件 <?xml version="1.0" encodi

Android实现用文字生成图片的示例代码

本文介绍了Android实现用文字生成图片的示例代码,分享给大家,具体如下: 效果图 我们先来看看效果图,可以看到下图由各种颜色的"美"字拼接而成,形成了一张不一样的图片. 原理 生成这种图片的原理很简单,但是当时看开源项目时愣是看不懂,因为没学过Python,但是仔细研究,终于能慢慢的理解该开源项目源码,并把它改写成Android平台的源代码.下面把这个算法的主要内容讲给大家,该算法大致原理如下: 1.根据原图片的大小和字体的大小创建一张空白图片 2.把原图片按字体的大小分成若干块,

Android自定义滑动验证条的示例代码

本文介绍了Android自定义滑动验证条的示例代码,分享给大家,具体如下: *注:不知道为什么,h5的标签在这里没用了,所以我也只能用Markdown的语法来写了 项目地址:https://github.com/994866755/handsomeYe.seekbar.github.io 需求: 在我们的某些应用中需要滑动验证.比如说这个样子的: 刚开始我也很懵逼要怎么去弄,结果我去看了一些人的代码,有人是用自定义viewgroup去做,就是viewgroup包含滑动块和滑动条.但我觉得太麻烦,

Android 给图片加上水印的示例代码(支持logo+文字)

本文介绍了Android 给图片加上水印的示例代码(支持logo+文字),分享给大家,具体如下: 现在我们想要往图片上打上水印,该水印应符合这样的需求的: 支持logo+文字: 文字信息支持多行展示: 用户可以选择水印在图片上的生成位置(左上.右上.右下和左下). 粗略的结构图低配版大概就长这样... 水印结构图.png 现在提供这样的一种思路去实现这一个需求,我们可以通过自定义一个view,view的布局中包含logo.公司名称和相关信息,这个view就是我们要打上图片的水印. 这样的一个vi

Android TextView实现词组高亮的示例代码

本文介绍了Android TextView实现词组高亮的示例代码,分享给大家,具体如下: HighlightTextView Android文本高亮控件,基于View实现. 特点 文本高亮 单词自动换行 高亮词组保持在同一行显示 效果如下: 主要逻辑: 两个 Paint 负责绘制不同的文字 在每次绘制之前计算将要绘制的文本是否会超出屏幕宽度,如果超出则换行 protected void onDraw(Canvas canvas) { super.onDraw(canvas); float x_d

Js判断H5上下滑动方向及滑动到顶部和底部判断的示例代码

向上滑动隐藏底部悬浮框,向下滑动显示悬浮框.使用pc端浏览器查看请把浏览器设置为手机浏览器模式. <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>手机端触屏手指滑动方向</title> <meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,us

Android自定义控件之翻转按钮的示例代码

本文介绍了Android自定义控件之翻转按钮的示例代码,分享给大家,具体如下: 先看一下效果 一.先定义控件的基本结构 这里我们定义一个容器,所以是在ViewGroup的基础上扩展. 简单起见,直接使用扩展自ViewGroup的LinearLayout,并将我们的控件扩展自LinearLayout. 1.按钮的基本布局如下 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr

Android视频悬浮窗口实现的示例代码

前言 本文例子实现了点击显示悬浮窗口,同时窗口可播放视频,拖动位置,点击关闭及返回 APP 页面,通过例子来讲述悬浮窗口实现原理及细节处理,效果图如下所示: 悬浮窗口.gif 原理 WindowManager 对 View 视图进行添加.移除.更新处理: WindowManager.LayoutParams 对窗口参数进行一系列设置. 实现 首先,需要添加相对应悬浮窗权限: <uses-permission android:name="android.permission.SYSTEM_A

Android实现强制下线功能的示例代码

一.回顾 上次连载写了两个类,一个类ActivityCollector.java用于管理所有的活动:一个类是BaseActivity.java作为所有活动的父类: 还有一个放在layout目录中的登录界面login.xml 二.登录页面的活动 接下来写一个登录页面的活动,继承自BaseActivity.java package com.example.broadcastbestpractice; import android.content.Intent; import android.os.B