Repository: KaiXuan666/WindowTree Branch: master Commit: 3eb6054c0979 Files: 79 Total size: 116.4 KB Directory structure: gitextract_oo05fiuo/ ├── .gitignore ├── .idea/ │ ├── codeStyles/ │ │ ├── Project.xml │ │ └── codeStyleConfig.xml │ ├── gradle.xml │ ├── misc.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── kaixuan/ │ │ └── windowtree/ │ │ └── ExampleInstrumentedTest.kt │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── kaixuan/ │ │ │ └── windowtree/ │ │ │ ├── KotlinCommon.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MyApp.kt │ │ │ ├── WindowTag.kt │ │ │ ├── activity/ │ │ │ │ ├── BaseActivity.kt │ │ │ │ ├── EmptyActivity.kt │ │ │ │ ├── NewsDetailActivity.kt │ │ │ │ └── NewsListActivity.kt │ │ │ └── fragment/ │ │ │ ├── ContactsFragment.kt │ │ │ ├── DynamicFragment.kt │ │ │ ├── MainFragment.kt │ │ │ ├── VipFragment.kt │ │ │ └── dynamic/ │ │ │ └── GoodFriendDynamicFragment.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── activity_news_detail.xml │ │ │ ├── activity_news_list.xml │ │ │ ├── fragment_msg.xml │ │ │ └── fragment_test.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── kaixuan/ │ └── windowtree/ │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── settings.gradle ├── windowtree_annotation/ │ ├── .gitignore │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── kaixuan/ │ └── windowtree_annotation/ │ ├── MyClass.java │ ├── annotation/ │ │ ├── Window.java │ │ └── WindowTypeAnnotation.java │ ├── enums/ │ │ └── WindowType.java │ └── model/ │ ├── WindowData.java │ └── WindowMeta.java ├── windowtree_compiler/ │ ├── .gitignore │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── kaixuan/ │ └── compiler/ │ └── WindowProcessor.java └── windowtree_library/ ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src/ ├── androidTest/ │ └── java/ │ └── com/ │ └── kaixuan/ │ └── windowtreelibrary/ │ └── ExampleInstrumentedTest.java ├── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── com/ │ │ └── kaixuan/ │ │ └── windowtreelibrary/ │ │ ├── WindowInfo.kt │ │ ├── WindowTree.kt │ │ ├── adapter/ │ │ │ └── DefaultJumpAdapter.kt │ │ ├── model/ │ │ │ └── UnReadCountEvent.kt │ │ ├── template/ │ │ │ ├── IJumpAdapter.kt │ │ │ ├── ILogger.java │ │ │ ├── IMain.java │ │ │ └── IWindowTreeLoad.java │ │ ├── thread/ │ │ │ ├── DefaultPoolExecutor.java │ │ │ └── DefaultThreadFactory.java │ │ └── util/ │ │ ├── ClassUtils.java │ │ ├── Consts.kt │ │ ├── DefaultLogger.java │ │ ├── TextUtils.java │ │ └── WindowTreeUtil.kt │ └── res/ │ └── values/ │ └── strings.xml └── test/ └── java/ └── com/ └── kaixuan/ └── windowtreelibrary/ └── ExampleUnitTest.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/caches/build_file_checksums.ser /.idea/libraries /.idea/modules.xml /.idea/workspace.xml .DS_Store /build /captures .externalNativeBuild ================================================ FILE: .idea/codeStyles/Project.xml ================================================ ================================================ FILE: .idea/codeStyles/codeStyleConfig.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: README.md ================================================ # WindowTree 只需使用注解,帮助你轻松维护树形界面的层级关系,管理你的界面结构,当你处于界面的任何位置时,都可以知道,我在哪里,我的父界面是谁,我的子界面是谁。甚至能够自动构建你的界面结构。 ## 我们经常会遇一些这样的问题: home界面下面有三个子界面A,B,C,他们三个业务功能内都会出现一个或多个未读消息或者通知,那么我们的home界面需要展示的未读消息数就应该是三个子界面未读消息数之和。 刚看到这个问题的时候会感觉很简单,我只需要在每次触发未读消息增减变化的时候,将本级界面和上一级界面的未读数量重新统计即可。当然,简单的需求是可以这么做,但是你有没有考虑过: 1. 当子界面A下级又有三个子界面A1,A2,A3的时候该怎么办? 2. 当用户没有一些界面的查看权限时,缺少了B和A2界面的浏览权限时,该怎么办? 3. 在界面构建时,如果发现用户没有A1,A2,A3的权限,那么其实A界面也不需要被构建,这样的工作,框架可以帮助我完成吗? 考虑到以上问题,如果用面向过程的思考方式出现一个解决一个,必然是事倍功半的,所以WindowTree就这样诞生了。 # WindowTree结构 ![avatar](https://img-blog.csdnimg.cn/20190302184300349.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2thaXh1YW5fZGFzaGVu,size_16,color_FFFFFF,t_70) windowTree将应用内的所有界面都视为一个Window,每个window都拥有与之关联的WindowInfo,借助WindowInfo,你可以完成灵活、强大的工作。 目前支持的功能: 1. 维护了父子界面的层级关系,你在应用的任意位置,都可以知道我的父界面是谁,我的子界面有几个等 2. 灵活的消息通讯,你可以在任意位置发送消息给任意界面,支持双向通讯,你可以知道接收者处理该消息的结果 3. 支持贯穿全局的未读消息小红点,一个父节点能够智能计算出他所拥有的所有子节点的未读消息之和,借助Kotlin的委托属性实现了数量变化实时通知更新! 4. 智能的权限管理,当用户未拥有a的子界面a1,a2的权限时,也将失去a的界面权限 5. 界面自动化搭建,你只需要使用注解定义好界面的层级关系,便可以调用api获取所有子界面,一个循环全部建立 6. 统一管理界面跳转,便于管理界面和埋点统计,减少重复代码 7. 支持Activity、Fragment、View、Dialog、PopupWindow... # WindowTree使用 添加依赖项: ``` apply plugin: 'kotlin-kapt' ... dependencies { kapt 'com.kaixuan:windowtree-compiler:1.0.0' implementation 'com.kaixuan:windowtree-library:1.0.0' ... } ``` 1. 在你应用的所有界面添加注解@Window,参数parentClass指定该界面的父节点(如当前是顶级节点,则不需要设置该属性),可选添加其他属性,index表示当前界面是父界面的第几个同类界面,name表示当前节点名字 ``` @Window(parentClass = MainActivity::class,index = 2,name = "联系人") class ContactsFragment : Fragment() ```
2. 在应用启动时,初始化WindowTree
``` WindowTree.init(MyApp.instance) ```
3. - 使用kotlin时,可直接在界面类(Activity、Fragment等)中使用扩展属性mWindowInfo拿到当前界面对应的WindowInfo - 使用java时,使用WindowTree.with(this)获取当前界面对应的WindowInfo
4. 如需接收消息,需要给当前节点设置setEventListener ``` mWindowInfo.setEventListener { sender, sendData -> if (sendData is UnReadCountEvent){ tv_log.append("未读消息:${sender.name}的未读消息发生变化,数量变化=${sendData.change}\n") updateUnReadCount() return@setEventListener "ok 我已收到并处理完毕" // 支持返回给消息发送者一个回信 } return@setEventListener null } ``` windowTree支持消息接收者返回一个结果的应答,告知事件处理结果
5. 拿到我的父节点或子节点对象,使用当前的WindowInfo对象可以轻松找到父节点和子节点,如: ``` mWindowInfo.parent mWindowInfo.child ```
6. 界面自动构建,如果你使用TabLayout管理你的界面,只需要以下代码即可将当前界面的所有子界面加入到Tab ``` tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener{ override fun onTabReselected(tab: TabLayout.Tab?) { } override fun onTabUnselected(tab: TabLayout.Tab?) { } override fun onTabSelected(tab: TabLayout.Tab?) { mWindowInfo.jump(tab!!.position,WindowType.FRAGMENTV4) } }) mWindowInfo.filterChildByWindowType(WindowType.FRAGMENTV4).forEach { window -> tabLayout.addTab(tabLayout.newTab().setText(window.name).setTag(window)) } ```
7. 界面跳转控制 ``` mWindowInfo.jump(0,WindowType.FRAGMENTV4) ``` 这段代码表示,跳转到我的第1个Fragment类型的子界面 DefaultJumpAdapter中默认实现了一些跳转逻辑,你可以继承它实现自己的特殊逻辑

如果你有更好的建议欢迎与我联系!thank you!kaixuanapp@163.com github:https://github.com/KaiXuan666/WindowTree csdn:https://blog.csdn.net/kaixuan_dashen ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 28 defaultConfig { applicationId "com.kaixuan.windowtree" minSdkVersion 15 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation project(path: ':windowtree_annotation') kapt project(':windowtree_compiler') implementation project(':windowtree_library') implementation 'com.android.support:design:28.0.0' // kapt 'com.kaixuan:windowtree-compiler:1.0.0' // implementation 'com.kaixuan:windowtree-library:1.0.0' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/com/kaixuan/windowtree/ExampleInstrumentedTest.kt ================================================ package com.kaixuan.windowtree import android.support.test.InstrumentationRegistry import android.support.test.runner.AndroidJUnit4 import org.junit.Test import org.junit.runner.RunWith import org.junit.Assert.* /** * Instrumented test, which will execute on an Android device. * * See [testing documentation](http://d.android.com/tools/testing). */ @RunWith(AndroidJUnit4::class) class ExampleInstrumentedTest { @Test fun useAppContext() { // Context of the app under test. val appContext = InstrumentationRegistry.getTargetContext() assertEquals("com.kaixuan.windowtree", appContext.packageName) } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/KotlinCommon.kt ================================================ package com.kaixuan.windowtree import android.widget.Toast fun showToast(msg : String){ Toast.makeText(MyApp.instance,msg,Toast.LENGTH_SHORT).show() } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/MainActivity.kt ================================================ package com.kaixuan.windowtree import android.os.Bundle import android.support.design.widget.TabLayout import android.text.method.ScrollingMovementMethod import android.util.Log import android.view.View import android.view.ViewGroup import android.widget.Button import com.kaixuan.windowtree.activity.BaseActivity import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtree_annotation.enums.WindowType import com.kaixuan.windowtreelibrary.WindowInfo import com.kaixuan.windowtreelibrary.WindowTree import com.kaixuan.windowtreelibrary.mWindowInfo import com.kaixuan.windowtreelibrary.model.UnReadCountEvent import kotlinx.android.synthetic.main.activity_main.* @Window class MainActivity : BaseActivity() { lateinit var with: WindowInfo<*> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) tv_log.movementMethod = ScrollingMovementMethod.getInstance(); btnInit.setOnClickListener { init() } btnCreateLayout.setOnClickListener { _ -> WindowTree.instance.hasPageAuthorityFun = { it == -1L } if (WindowTree.hasInit) { bindTabLayout() initActivityButton() } else { showToast("请先初始化") } } btnCreateLayout.setOnLongClickListener { _ -> // 用户的页面权限,一般通过登录接口获取 val userAuthority = listOf(-1L, 1L, 2L, 3L, 4L) WindowTree.instance.hasPageAuthorityFun = { userAuthority.contains(it) } if (WindowTree.hasInit) { bindTabLayout() initActivityButton() } else { showToast("请先初始化") } true } btnGc.setOnClickListener { System.gc() } btnDestroy.setOnClickListener { release() } } fun init() { if (WindowTree.hasInit) { showToast("已经初始化过") return } WindowTree.init(MyApp.instance) with = mWindowInfo mWindowInfo.frameLayoutId = frameLayout.id initEventListener() } fun initEventListener() { with.setEventListener { sender, sendData -> if (sendData is UnReadCountEvent) { tv_log.append("未读消息:${sender.name}的未读消息发生变化,数量变化=${sendData.change}\n") updateUnReadCount() return@setEventListener null } when (sender) { // 1、判断是自己的孩子发来的消息 in with.child -> { when (sendData) { // 2、判断发来消息的数据类型,你也可以定义msgCode或其他数据类型来进行判断,此处我为了偷懒 is String -> { tv_log.append("子模块${sender.name}发来了消息,内容=${sendData}\n") } is Int -> { } } } } return@setEventListener "ok 我已收到并处理完毕" // 支持返回给消息发送者一个回信 } } fun bindTabLayout() { if (tabLayout.tabCount != 0) { showToast("不能重复添加tab") return } tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab?) { } override fun onTabUnselected(tab: TabLayout.Tab?) { } override fun onTabSelected(tab: TabLayout.Tab?) { Log.e("onTabSelected", tab!!.tag.toString()) mWindowInfo.jump(tab!!.position, WindowType.FRAGMENTV4) } }) // 自动布局到TabLayout,两种方式都可以实现 // with.child.forEach { // if (it.windowType == WindowType.FRAGMENTV4){ // tabLayout.addTab(tabLayout.newTab().setText(it.name)) // } // } mWindowInfo.filterChildByWindowType(WindowType.FRAGMENTV4).filter { WindowTree.hasAuthority(it.pageAuthority) } .forEach { window -> tabLayout.addTab(tabLayout.newTab().setText(window.name).setTag(window)) } } fun initActivityButton() { llActivity.visibility = View.VISIBLE if (llActivity.childCount == 0) { // 过滤子Window自动进行布局 mWindowInfo.filterChildByWindowType(WindowType.ACTIVITY).forEach { window -> llActivity.addView(Button(this).apply { text = "打开 ${window.name}" setOnClickListener { with.jump(window) } // 注:此处不能使用mWindowInfo获取当前windowInfo对象,因为此处的this指代的是View Button }, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) } } } /** * 更新未读消息显示 */ fun updateUnReadCount() { val calcChildUnReadCount = mWindowInfo.calcChildUnReadCount() supportActionBar!!.title = if (calcChildUnReadCount != 0) "新消息:$calcChildUnReadCount" else "WindowTree" (0 until tabLayout.tabCount).forEach { val windowInfo = tabLayout.getTabAt(it)!!.tag as WindowInfo<*> val count = windowInfo.calcChildUnReadCount() tabLayout.getTabAt(it)!!.text = windowInfo.name + if (count == 0) "" else "($count)" } (0 until llActivity.childCount).forEach { val findChildByIndex = mWindowInfo.findChildByIndex(it, WindowType.ACTIVITY)!! (llActivity.getChildAt(it) as Button).apply { text = "打开 ${findChildByIndex.name}" val count = findChildByIndex.calcChildUnReadCount() if (count != 0) { append("($count)") } } } } override fun onBackPressed() { super.onBackPressed() } fun release() { supportActionBar!!.title = "WindowTree" WindowTree.destroy() llActivity.visibility = View.GONE llActivity.removeAllViews() tabLayout.removeAllTabs() tabLayout.clearOnTabSelectedListeners() frameLayout.removeAllViews() System.gc() tv_log.text = "" } override fun onDestroy() { release() super.onDestroy() } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/MyApp.kt ================================================ package com.kaixuan.windowtree import android.app.Application class MyApp : Application() { companion object { lateinit var instance : MyApp; } override fun onCreate() { super.onCreate() instance = this } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/WindowTag.kt ================================================ package com.kaixuan.windowtree class WindowTag( var unReadMsgCount : Int = 0, var pageAuthority : Long = 0 ){ } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/activity/BaseActivity.kt ================================================ package com.kaixuan.windowtree.activity import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.util.Log open class BaseActivity : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Log.i(this.javaClass.simpleName,"onCreate") } override fun onStart() { super.onStart() Log.i(this.javaClass.simpleName,"onStart") } override fun onResume() { super.onResume() Log.i(this.javaClass.simpleName,"onResume") } override fun onPause() { super.onPause() Log.i(this.javaClass.simpleName,"onPause") } override fun onStop() { super.onStop() Log.i(this.javaClass.simpleName,"onStop") } override fun onDestroy() { super.onDestroy() Log.i(this.javaClass.simpleName,"onDestroy") } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/activity/EmptyActivity.kt ================================================ package com.kaixuan.windowtree.activity import android.support.v7.app.AppCompatActivity import android.os.Bundle import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo @Window(parentClassName = "com.kaixuan.windowtree.MainActivity",name = "空白界面",index = 2) class EmptyActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.fragment_test) supportActionBar!!.title = mWindowInfo.name } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/activity/NewsDetailActivity.kt ================================================ package com.kaixuan.windowtree.activity import android.os.Bundle import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo import com.kaixuan.windowtreelibrary.model.UnReadCountEvent import kotlinx.android.synthetic.main.activity_news_detail.* @Window(parentClass = NewsListActivity::class,name = "新闻详情",index = 3) class NewsDetailActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_news_detail) supportActionBar!!.title = mWindowInfo.name + mWindowInfo.getTag() tv_title.text = mWindowInfo.getTag() as String mWindowInfo.unReadMsgCount = mWindowInfo.bundle.getInt("unReadCount") tv_unReadCount.text = "未读数量:${mWindowInfo.unReadMsgCount}" mWindowInfo.setEventListener { sender, sendData -> if (sendData is UnReadCountEvent){ tv_unReadCount.text = "未读数量:${mWindowInfo.unReadMsgCount}" } } btn_unReadAdd.setOnClickListener { mWindowInfo.unReadMsgCount ++ } btn_dealUnRead.setOnClickListener { mWindowInfo.unReadMsgCount = 0 } } override fun onDestroy() { mWindowInfo.release() super.onDestroy() } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/activity/NewsListActivity.kt ================================================ package com.kaixuan.windowtree.activity import android.os.Bundle import android.support.v7.recyclerview.extensions.ListAdapter import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.ViewGroup import android.widget.TextView import com.kaixuan.windowtree.MainActivity import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.activity_news_list.* @Window(parentClass = MainActivity::class,name = "新闻列表",index = 1) class NewsListActivity : BaseActivity() { val newsList = 0..200 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_news_list) supportActionBar!!.title = mWindowInfo.name recyclerView.layoutManager = LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false) recyclerView.adapter = object : RecyclerView.Adapter(){ override fun onCreateViewHolder(p0: ViewGroup, p1: Int): RecyclerView.ViewHolder { return object : RecyclerView.ViewHolder(LayoutInflater.from(this@NewsListActivity).inflate(R.layout.support_simple_spinner_dropdown_item,p0,false)){} } override fun getItemCount(): Int = newsList.count() override fun onBindViewHolder(p0: RecyclerView.ViewHolder, p1: Int) { (p0.itemView as TextView).let {textView -> textView.text = "Hello,这里是新闻啊啊啊啊啊啊啊啊 ${p1}" textView.setOnClickListener { val childByIndex = mWindowInfo.findChildByIndex(0)!! childByIndex.setTag(textView.text.toString()) childByIndex.bundle.putInt("unReadCount",p1) mWindowInfo.jump(childByIndex) } } } } } override fun onDestroy() { mWindowInfo.release() super.onDestroy() } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/fragment/ContactsFragment.kt ================================================ package com.kaixuan.windowtree.fragment import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.kaixuan.windowtree.MainActivity import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.fragment_test.* @Window(parentClass = MainActivity::class,index = 2,name = "联系人") class ContactsFragment : Fragment() { var mView : View? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = mView ?: inflater.inflate(R.layout.fragment_test,container,false).apply { mView = this } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) tv_title.text = "我是" + mWindowInfo.getClazz()!!.simpleName btn_send.setOnClickListener { mWindowInfo.unReadMsgCount ++ val response = mWindowInfo.sendData("hello,我是${javaClass.simpleName}", mWindowInfo.parent!!) tv_log.append("收到了回信:${mWindowInfo.parent!!.getClazz()!!.simpleName}:$response\n") } btn_resetUnReadCount.setOnClickListener { mWindowInfo.unReadMsgCount = 0 } } override fun onDestroyView() { mWindowInfo.release() super.onDestroyView() } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/fragment/DynamicFragment.kt ================================================ package com.kaixuan.windowtree.fragment import android.os.Bundle import android.support.v4.app.Fragment import android.text.method.ScrollingMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.kaixuan.windowtree.MainActivity import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.fragment_test.* @Window(parentClass = MainActivity::class,index = 3,name = "动态") class DynamicFragment : Fragment() { var mView : View? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = mView ?: inflater.inflate(R.layout.fragment_test,container,false).apply { mView = this } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { tv_log.movementMethod = ScrollingMovementMethod.getInstance(); tv_title.text = "我是" + mWindowInfo.getClazz()!!.simpleName btn_send.setOnClickListener { mWindowInfo.unReadMsgCount ++ val response = mWindowInfo.sendData("hello,我是${javaClass.simpleName}", mWindowInfo.parent!!) tv_log.append("收到了回信:${mWindowInfo.parent!!.getClazz()!!.simpleName}:$response\n") } btn_resetUnReadCount.setOnClickListener { mWindowInfo.unReadMsgCount = 0 } } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/fragment/MainFragment.kt ================================================ package com.kaixuan.windowtree.fragment import android.os.Bundle import android.support.v4.app.Fragment import android.text.method.ScrollingMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.kaixuan.windowtree.MainActivity import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.WindowInfo import com.kaixuan.windowtreelibrary.WindowTree import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.fragment_test.* @Window(parentClass = MainActivity::class,index = 1,name = "主页") class MainFragment : Fragment() { lateinit var with : WindowInfo var mView : View? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = mView ?: inflater.inflate(R.layout.fragment_test,container,false).apply { mView = this } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { with = WindowTree.with(this)!! val t = with.setTag("") tv_log.movementMethod = ScrollingMovementMethod.getInstance(); tv_title.text = "我是" + mWindowInfo!!.getClazz()!!.simpleName btn_send.setOnClickListener { mWindowInfo.unReadMsgCount ++ val response = with.sendData("hello,我是${javaClass.simpleName}", with.parent!!) tv_log.append("收到了回信:${with.parent!!.getClazz()!!.simpleName}:${response}\n") } btn_resetUnReadCount.setOnClickListener { mWindowInfo.unReadMsgCount = 0 } } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/fragment/VipFragment.kt ================================================ package com.kaixuan.windowtree.fragment import android.os.Bundle import android.support.v4.app.Fragment import android.text.method.ScrollingMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.kaixuan.windowtree.MainActivity import com.kaixuan.windowtree.R import com.kaixuan.windowtree_annotation.annotation.Window import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.fragment_test.* @Window(parentClass = MainActivity::class,index = 3,name = "Vip隐藏界面",pageAuthority = 1) class VipFragment : Fragment() { var mView : View? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = mView ?: inflater.inflate(R.layout.fragment_test,container,false).apply { mView = this } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { tv_log.movementMethod = ScrollingMovementMethod.getInstance(); tv_title.text = "我是Vip界面,一般人没有权限打开我" btn_send.setOnClickListener { mWindowInfo.unReadMsgCount ++ val response = mWindowInfo.sendData("hello,我是${javaClass.simpleName},pageAuthority=${mWindowInfo.pageAuthority}", mWindowInfo.parent!!) tv_log.append( "收到了回信:${mWindowInfo.parent!!.getClazz()!!.simpleName}:$response\n") } btn_resetUnReadCount.setOnClickListener { mWindowInfo.unReadMsgCount = 0 } } } ================================================ FILE: app/src/main/java/com/kaixuan/windowtree/fragment/dynamic/GoodFriendDynamicFragment.kt ================================================ package com.kaixuan.windowtree.fragment.dynamic import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.kaixuan.windowtree.R import com.kaixuan.windowtreelibrary.mWindowInfo import kotlinx.android.synthetic.main.fragment_msg.* class GoodFriendDynamicFragment : Fragment() { var mView : View? = null override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = mView ?: inflater.inflate(R.layout.fragment_msg,container,false).apply { mView = this } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { updateMsgCount() mWindowInfo.setEventListener { sender, sendData -> mWindowInfo.unReadMsgCount++ updateMsgCount() } } fun updateMsgCount(){ tv_msg_tips.text = "我有${mWindowInfo.unReadMsgCount}条未读消息" } } ================================================ FILE: app/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable-v24/ic_launcher_foreground.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_main.xml ================================================