1.Constant常量定义类

1.1.源代码

public class Constant {

    public static final String USER_AGENT_MOBILE = "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Mobile Safari/537.36";

    public static final String USER_AGENT_PC = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36";

    public static final int[] TAG_COLORS = new int[]{
Color.parseColor("#90C5F0"),
Color.parseColor("#91CED5"),
Color.parseColor("#F88F55"),
Color.parseColor("#C0AFD0"),
Color.parseColor("#E78F8F"),
Color.parseColor("#67CCB7"),
Color.parseColor("#F6BC7E")
}; public static final int[] ICONS_DRAWABLES = new int[]{
R.mipmap.ic_launcher_circle,
R.mipmap.ic_launcher_rect,
R.mipmap.ic_launcher_square}; public static final String[] ICONS_TYPE = new String[]{"circle", "rect", "square"}; public static final int SLIDABLE_DISABLE = 0;
public static final int SLIDABLE_EDGE = 1;
public static final int SLIDABLE_FULL = 2; public static final String AS = "as";
public static final String CP = "cp"; public static final int NEWS_CHANNEL_ENABLE = 1;
public static final int NEWS_CHANNEL_DISABLE = 0;
}

1.2.作用介绍

  标签颜色存放成一个整型数组

  logo的三个不同形状,用整型数组来存放id

  图片类型用一个字符串数组来存放

  Slidable属性值用整型存放

  AS/CP,用字符串存放

  News_Channel属性,用整型存放

2.开源项目material-dialogs的引用

2.1.用到了这种效果

  参考文章:开源项目material-dialogs的使用。

  

2.2.导入引用

  compile 'com.afollestad.material-dialogs:commons:0.9.4.4'

2.3.具体使用

  可以参考上面那篇文章。

  

  

  

  

  

  等效果,功能强大,具体代码,点击我。

3.ActivityManager深入理解

3.1.这里碰到了一个类ActivityManager.TaskDescription

  然后百度了一下:

  

3.2.其他用法可以参考下面这篇文章。

  ActivityManager总结:http://blog.csdn.net/lanye11/article/details/52221359

4.BaseActivity分析

4.1.getWindow().setNavigationBarColor

  不知道setNavigationBarColor是什么意思

  找到了这张图。

  

4.2.android.R.id.home

  

  就是左上角的图标,一般就是一个左箭头。

4.3.按返回键,逐个出栈的方法

 @Override
public void onBackPressed() {
// Fragment 逐个出栈
int count = getSupportFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
} else {
getSupportFragmentManager().popBackStack();
}
}

4.4.在清单中声明启动页活动的别名 

     <activity
android:name=".SplashActivity"
android:configChanges="orientation|screenSize|uiMode"
android:label="@string/app_name"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
</activity> <activity-alias
android:name=".SplashActivity_circle"
android:enabled="true"
android:icon="@mipmap/ic_launcher_circle"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias> <activity-alias
android:name=".SplashActivity_rect"
android:enabled="false"
android:icon="@mipmap/ic_launcher_rect"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias> <activity-alias
android:name=".SplashActivity_square"
android:enabled="false"
android:icon="@mipmap/ic_launcher_square"
android:label="@string/app_name"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>

  可以看到,这里使用了<activity-alias>标签

  这里有3个标签,代表着圆形,矩形,正方形的启动页。

  所以这里每当修改了应用图标之后,这里就可以动态地变化启动图标了。

  这里有一个activity,但是写了4个<intent-filter>

  所以这招很管用。

  注意:要把第一个<intent-filter>中将<category android:name="android...LAUNCHER">删去。

  参考文章:activity-alias详解及应用。

4.5.android禁用和开启启动图标

  这个和上面的修改应用图标结合使用。

  当修改了应用图标,应该停止当前应用的进程。

  所以要kill掉当前应用,而且桌面图标不能生效,直到应用图标修改完成,图标也换了,然后就可以点了。

 getPackageManager().setComponentEnabledSetting(new ComponentName(BaseActivity.this, getPackageName() + act),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);

  参考文章:android禁用和开启四大组件的方法。

4.6.BaseActivity源代码

public class BaseActivity extends RxAppCompatActivity {
private static final String TAG="BaseActivity";
protected SlidrInterface slidrInterface;
private int iconType=-1; @Override
protected void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
//默认图标获取的是圆形circle
this.iconType=SettingUtil.getInstance().getCustomIconValue();
initSlidrable();
} @Override
protected void onResume(){
super.onResume();
//获取主题色
int color=SettingUtil.getInstance().getColor();
//获取图标形状,圆,矩,正
int drawable=Constant.ICONS_DRAWABLES[SettingUtil.getInstance().getCustomIconValue()];
if(getSupportActionBar()!=null){
//设置标题栏的颜色
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color));
}
//如果SDK版本>=21,还要设置状态栏的颜色
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){
getWindow().setStatusBarColor(CircleView.shiftColorDown(color));
//TaskDescription==>用于在最近的任务列表中设置和检索当前活动的信息
ActivityManager.TaskDescription taskDescription=new ActivityManager.TaskDescription(
getString(R.string.app_name),
BitmapFactory.decodeResource(getResources(),drawable),
color
);
setTaskDescription(taskDescription);
//setNavigationBar是底部导航栏,模拟器上会有
if(SettingUtil.getInstance().getNavBar()){
getWindow().setNavigationBarColor(CircleView.shiftColorDown(color));
}else{
getWindow().setNavigationBarColor(Color.BLACK);
}
}
} @Override
public boolean onOptionsItemSelected(MenuItem item){
if(item.getItemId()==android.R.id.home){
onBackPressed();
}
return super.onOptionsItemSelected(item);
} @Override
public void onBackPressed(){
//Fragment逐个出栈
int count=getSupportFragmentManager().getBackStackEntryCount();
if(count==0){
super.onBackPressed();
}else{
getSupportFragmentManager().popBackStack();
}
} @Override
protected void onStop(){ //如果iconType不为默认的圆形了
if(iconType!=SettingUtil.getInstance().getCustomIconValue()){
new Thread(new Runnable() {
@Override
public void run() {
//前提是在清单中已经完成配置别名
String act=".SplashActivity_";
for(String s:Constant.ICONS_TYPE){
getPackageManager().setComponentEnabledSetting(new ComponentName(BaseActivity.this,getPackageName()+act+s),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
} act+=Constant.ICONS_TYPE[SettingUtil.getInstance().getCustomIconValue()]; getPackageManager().setComponentEnabledSetting(new ComponentName(BaseActivity.this,getPackageName()+act),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
}
}).start();
} super.onStop();
} /**
* 初始化Toolbar
*/
protected void initToolbar(Toolbar toolbar, boolean homeAsUpEnabled, String title){
toolbar.setTitle(title);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(homeAsUpEnabled);
} /**
* 初始化滑动返回
*/
protected void initSlidrable(){
int isSlidable=SettingUtil.getInstance().getSlidable();
if(isSlidable!= Constant.SLIDABLE_DISABLE){
SlidrConfig config=new SlidrConfig.Builder()
.edge(isSlidable==Constant.SLIDABLE_EDGE)
.build();
slidrInterface= Slidr.attach(this,config);
}
} }

5.MainActivity分析

5.1.支持android材料设计,以及卡片设计模式

    implementation "com.android.support:appcompat-v7:${SUPPORT_LIBRARY_VERSION}"
implementation "com.android.support:cardview-v7:${SUPPORT_LIBRARY_VERSION}"
implementation "com.android.support:design:${SUPPORT_LIBRARY_VERSION}"

  在build.gradle中添加这些引用即可。

5.2.android:fitsSystemWIndows="true"

  这个View的所有padding属性失效

  可以用于沉浸式状态栏。

  参考文章:fitsSystemWindows属性讲解。

5.3.android:openDrawer

  这个在布局DrawerLayout中会用到。

  在布局中可以利用这个属性控制抽屉布局显示出来。

  参考文章:Android的Material Design初次尝试。

5.4.CoordinatorLayout有什么用

  CoordinatorLayout称为“super-powered FrameLayout”基本实现两个功能:

  1.作为顶层布局

  2.调度协调子布局

  参考文章:android CoordinatorLayout使用。

5.5.app:elevation="0dp"

  给控件,如AppBarLayout去掉阴影效果。

  参考文章:AppCompat Toolbar控件去掉阴影。

5.6.app:layout_scrollFlags=""

  给toolbar设置混动模式

  参考文章:Android详细分析AppBarLayout。

  app:popupTheme=""

  toolbar弹出菜单样式

  参考文章:app:popupTheme作用。

5.7.app:layout_behavior=""

   android.support.design.widget.AppBarLayout$ScrollingViewBehavior

  这里定义了布局的行为,这是一个官方的行为

  参考这篇文章了解这个行为。

5.8.设置底部导航栏

 <android.support.design.widget.BottomNavigationView
android:id="@+id/bottom_navigation"
style="@style/Widget.Design.BottomNavigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:background="@color/viewBackground"
app:elevation="16dp"
app:itemIconTint="@drawable/nav_item_color_state"
app:itemTextColor="@drawable/nav_item_color_state"
app:layout_behavior="com.meiji.toutiao.widget.behavior.BottomNavigationBehavior"
app:menu="@menu/bottom_navigation_main" />

  这里用了官方的一个BottomNavigationView,本例中就是底部导航栏的作用。

  app:itemIconTint来设置图标点击的颜色变化。

  app:itemTextColor来设置文字点击变化。

  这里需要有定义一个样式文件==>nav_item_color_state.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/Blue_Grey" android:state_checked="true"/>
<item android:color="@color/textColorPrimary" android:state_checked="false"/>
</selector>

  然后还需要一个菜单布局文件:@menu/bottom_navigation_main

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_news"
android:enabled="true"
android:icon="@drawable/ic_newspaper_white_24dp"
android:title="@string/title_news"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_photo"
android:enabled="true"
android:icon="@drawable/ic_gallery_white_24dp"
android:title="@string/title_photo"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_video"
android:enabled="true"
android:icon="@drawable/ic_youtube_white_24dp"
android:title="@string/title_video"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_media"
android:enabled="true"
android:icon="@drawable/ic_library_books_white_24dp"
android:title="@string/title_media"
app:showAsAction="ifRoom"/>
</menu>

  app:showAsAction的作用就是如果就空间就显示,如果没空间就在右边的三个点中。

5.9.左侧菜单栏

<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/nav_menu"/>

  采用了NavigationView布局方式。

  左侧菜单栏的顶部利用app:headerLayout来嵌套布局。

  

5.10.布局运行预览

                      

5.11.如何禁用BottomNavigationView换挡模式?

  就是下方的图标是没有汉字的,如何才能图标和文字一起显示呢,写了这个类后,一行代码即可搞定。

  参考文章:

  https://stackoverflow.com/questions/40176244/how-to-disable-bottomnavigationview-shift-mode

  需要新建一个BottomNavigationView帮助类

public class BottomNavigationViewHelper {

    public static void disableShiftMode(BottomNavigationView view) {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
try {
Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
shiftingMode.setAccessible(true);
shiftingMode.setBoolean(menuView, false);
shiftingMode.setAccessible(false);
for (int i = 0; i < menuView.getChildCount(); i++) {
BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
//noinspection RestrictedApi
item.setShiftingMode(false);
// set once again checked value, so view will be updated
//noinspection RestrictedApi
item.setChecked(item.getItemData().isChecked());
}
} catch (NoSuchFieldException e) {
Log.e("BNVHelper", "Unable to get shift mode field", e);
} catch (IllegalAccessException e) {
Log.e("BNVHelper", "Unable to change value of shift mode", e);
}
}
}

  然后再调用一下这个函数即可。

 bottom_navigation = (BottomNavigationView) findViewById(R.id.bottom_navigation);
BottomNavigationViewHelper.disableShiftMode(bottom_navigation);

5.12.标题栏左上角引导左侧菜单栏

  五行代码即可搞定。

     drawer_layout = findViewById(R.id.drawer_layout) as DrawerLayout
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout!!.addDrawerListener(toggle)
toggle.syncState()

5.13.解决toolbar.inflateMenu不生效的问题

  参考文章:http://blog.csdn.net/amd123456789/article/details/52474984

  

  其实上面只是为了测试

  真实情况还是要加,这个项目一定要重写下面这个函数,才有显示搜索图标

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_activity_main, menu);
return true;
}

5.14.使用第三方库taptargetview

             

  标题栏点击特效。

  参考文章:安卓taptargetview。

  高亮功能提示效果。

  implementation 'com.getkeepsafe.taptargetview:taptargetview:1.9.1'

5.15.利用TapTarget设置引导用户页面 

private void showTapTarget() {
final Display display = getWindowManager().getDefaultDisplay();
final Rect target = new Rect(
0,
display.getHeight(),
0,
display.getHeight());
target.offset(display.getWidth() / 8, -56); // 引导用户使用
TapTargetSequence sequence = new TapTargetSequence(this)
.targets(
TapTarget.forToolbarMenuItem(toolbar, R.id.action_search, "点击这里进行搜索")
.dimColor(android.R.color.black)
.outerCircleColor(R.color.colorPrimary)
.drawShadow(true)
.id(1),
TapTarget.forToolbarNavigationIcon(toolbar, "点击这里展开侧栏")
.dimColor(android.R.color.black)
.outerCircleColor(R.color.colorPrimary)
.drawShadow(true)
.id(2),
TapTarget.forBounds(target, "点击这里切换新闻", "双击返回顶部\n再次双击刷新当前页面")
.dimColor(android.R.color.black)
.outerCircleColor(R.color.colorPrimary)
.targetRadius(60)
.transparentTarget(true)
.drawShadow(true)
.id(3)
).listener(new TapTargetSequence.Listener() {
@Override
public void onSequenceFinish() {
SettingUtil.getInstance().setIsFirstTime(false);
} @Override
public void onSequenceStep(TapTarget lastTarget, boolean targetClicked) { } @Override
public void onSequenceCanceled(TapTarget lastTarget) {
SettingUtil.getInstance().setIsFirstTime(false);
}
});
sequence.start();
}

5.16.横竖屏切换保存数据==>重写onSaveInstanceState

 @Override
protected void onSaveInstanceState(Bundle outState) {
// recreate 时记录当前位置 (在 Manifest 已禁止 Activity 旋转,所以旋转屏幕并不会执行以下代码)
outState.putInt(POSITION, position);
outState.putInt(SELECT_ITEM, bottom_navigation.getSelectedItemId());
}

6.目前效果

6.1.创建好了SplashActivity+MainActivity

  但是具体的Fragment一个都还没有实现。

  实现了一个左侧菜单+顶部标题栏+底部导航栏

6.2.GIF图示

  

  

TouTiao开源项目 分析笔记2的更多相关文章

  1. TouTiao开源项目 分析笔记6

    1.NewsChannelBean简单类笔记 1.1.Comparable接口的实现和使用 参考文章:Comparable接口的实现和使用. 因为NewsChannelBean实现了Comparabl ...

  2. TouTiao开源项目 分析笔记4==>一个简单APP 整体常用框架

    1.效果预览 1.1.如下图所以,到目前为止所有的功能. 2.从InitApp开始->SplashActivity->MainActivity 2.1.InitApp源代码.这是整个项目的 ...

  3. TouTiao开源项目 分析笔记15 新闻详情之两种类型的实现

    1.预览效果 1.1.首先看一下需要实现的效果. 第一种,文字类型新闻. 第二种,图片类型新闻. 1.2.在NewsArticleTextViewBinder中设置了点击事件 RxView.click ...

  4. TouTiao开源项目 分析笔记12 从总体到局部 构建视频主页面

    1.构建视频主列表的整体碎片VideoTabLayout 1.1.首先创建一个VideoTabLayout package com.jasonjan.headnews.module.video; im ...

  5. TouTiao开源项目 分析笔记10 实现通用普通文章片段页面

    1.RxJava的Observable数据操作符总结 1.1.Map操作符 Map操作符对原始Observable发射的没一项数据应用一个你选择的函数, 然后返回一个发射这些结果的Observable ...

  6. TouTiao开源项目 分析笔记1

    1.InitApp==>项目的入口Application 1.1.继承了MultiDexApplication 超过65K方法的APP,会遇到65535的错误.原因就是为了支持比较大型的APP而 ...

  7. TouTiao开源项目 分析笔记18 视频详情页面

    1.效果预览 1.1.需要做到的真实效果 1.2.触发的点击事件 在MediaArticleVideoViewBinder的每一个item点击事件中: VideoContentActivity.lau ...

  8. TouTiao开源项目 分析笔记17 新闻媒体专栏

    1.效果预览 1.1.要实现的效果 1.2.如何调转到新闻媒体专栏 点击右上角的用户图标. 在新闻详情页面的Fragment的菜单点击事件中触发. case R.id.action_open_medi ...

  9. TouTiao开源项目 分析笔记16 新闻评论

    1.要达到的效果 1.1.主要效果图 点击了标题栏的消息图标后,然后会跳转到评论详情的页面. 1.2.触发的点击事件 在新闻详情的片段中的菜单点击事件中 设置上方标题栏的消息标的监听事件 case R ...

随机推荐

  1. Linux pptpd 的 iptables 包过滤设置

    用Centos架设了一台pptpd vpn服务器,信息如下: 服务器IP 192.168.100.1 /24 网关 192.168.100.254(NAT防火墙,将 <外网IP>:1723 ...

  2. Android 监听APP进入后台或切换到前台方案对比

    在我们开发的过程中,经常会遇到需要我们判断app进入后台,或者切换到前台的情况.比如我们想判断app切换到前台时,显示一个解锁界面,要求用户输入解锁密码才能继续进行操作:我们想判断app切换到后台,记 ...

  3. TeamViewer安装使用

    1.下载安装包 官网下载最新安装包 2.安装步骤 3.连接 输入密码即可控制伙伴电脑.

  4. XCode 如何真机运行别人的demo项目

    iOS应用安装到真机需要证书和mobileprovision 文件,拿到别人的项目 是没有这些的 ,也就运行不起来. 要想运行起来, 需要选中项目,  target - > 修改 bundlei ...

  5. 缺陷=bug?

    Defect(缺陷):是指静态处在于软件工作产品(文档.代码)中的错误,也指软件运行时由于这些错误被激发导致的软件产品与其属性的偏离现象. Bug:Bug通常是软件缺陷(Defect)导致的一些软件故 ...

  6. DOM笔记(十一):JavaScript对象的基本认识和创建

    一.什么是对象? 面 向对象(Object-Oriented,OO)的语言有一个标志,那就是都有类的概念,例如C++.Java等:但是ECMAScript没有类的概 念.ECMAScript-262把 ...

  7. 官方发布PHP语法规范

    PHP语言已经存在了超过20年,显然是世界上最流行的编程语言之一.PHP绝对是互联网服务器端web编程的通用语. 虽然有广泛的user-documentation,PHP语言总是错过语言规范.这并不是 ...

  8. spring教程(一):简单实现(转)

    转:https://www.cnblogs.com/Lemon-i/p/8398263.html  一.概念介绍 1. 一站式框架:管理项目中的对象.spring框架性质是容器(对象容器) 2. 核心 ...

  9. Mybatis之批量更新操作

    更新单条记录 UPDATE course SET name = 'course1' WHERE id = 'id1'; 更新多条记录的同一个字段为同一个值 UPDATE course SET name ...

  10. Linux tmpwatch命令

    Linux tmpwatch命令 作为系统管理员,很多时候需要定期清理一定规则的文件,比如过期的日志,过期的归档,已备份的文件等等. 如果使用一定的匹配规则,找出这些文件,然后再传递给rm命令,其实是 ...