├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── andnext_markdown-debug.aar
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── brick
│ │ └── app
│ │ ├── App.kt
│ │ ├── component
│ │ ├── ComponentFragment.kt
│ │ ├── coordinator
│ │ │ ├── CoordinatorLayoutActivity1.kt
│ │ │ └── CoordinatorLayoutActivity2.kt
│ │ ├── extra
│ │ │ ├── ExtraComponentActivity.kt
│ │ │ └── page
│ │ │ │ ├── EmbededPage.kt
│ │ │ │ ├── GlidePage.kt
│ │ │ │ └── SmartRefreshPage.kt
│ │ ├── layout
│ │ │ ├── LayoutActivity.kt
│ │ │ └── page
│ │ │ │ ├── ColumnPage.kt
│ │ │ │ ├── ConstraintPage.kt
│ │ │ │ ├── FlexboxPage.kt
│ │ │ │ ├── RelativePage.kt
│ │ │ │ └── RowPage.kt
│ │ ├── list
│ │ │ ├── list
│ │ │ │ ├── ListActivity.kt
│ │ │ │ └── page
│ │ │ │ │ ├── ComplexStatefulListPage.kt
│ │ │ │ │ └── StatefulListPage.kt
│ │ │ └── simple
│ │ │ │ ├── SimpleListActivity.kt
│ │ │ │ └── page
│ │ │ │ ├── GridListPage.kt
│ │ │ │ ├── HorizontalListPage.kt
│ │ │ │ ├── ScrollViewPage.kt
│ │ │ │ └── VerticalListPage.kt
│ │ └── pager
│ │ │ ├── PagerActivity.kt
│ │ │ └── page
│ │ │ ├── FragmentPagerPage.kt
│ │ │ ├── LoopViewPagerPage.kt
│ │ │ ├── TabLayoutViewPagerPage.kt
│ │ │ └── ViewPagerPage.kt
│ │ ├── extra
│ │ ├── ExtraFragment.kt
│ │ ├── about
│ │ │ ├── AboutActivity.kt
│ │ │ └── AboutPage.kt
│ │ ├── counter
│ │ │ ├── CounterActivity.kt
│ │ │ ├── CounterPage.kt
│ │ │ └── CounterPageViewModel.kt
│ │ └── list
│ │ │ ├── LongListActivity.kt
│ │ │ └── LongListPage.kt
│ │ ├── helper
│ │ ├── HelperFragment.kt
│ │ ├── animator
│ │ │ ├── AnimatorHelperActivity.kt
│ │ │ └── page
│ │ │ │ └── AnimatorPage.kt
│ │ ├── clip
│ │ │ ├── ClipAndShadowHelperActivity.kt
│ │ │ └── page
│ │ │ │ ├── ClipPage.kt
│ │ │ │ └── ShadowPage.kt
│ │ ├── color
│ │ │ ├── ColorAndDrawableHelperActivity.kt
│ │ │ └── page
│ │ │ │ ├── ColorPage.kt
│ │ │ │ └── DrawablePage.kt
│ │ └── spannable
│ │ │ ├── SpannableHelperActivity.kt
│ │ │ └── page
│ │ │ └── SpannablePage.kt
│ │ ├── main
│ │ ├── MainActivity.kt
│ │ ├── MainFragmentList.kt
│ │ ├── MainItemBean.kt
│ │ └── MainPage.kt
│ │ └── widget
│ │ ├── CommonKTX.kt
│ │ ├── Markdown.kt
│ │ ├── MultiTabViewPager.kt
│ │ ├── SeekValue.kt
│ │ └── TopBar.kt
│ └── res
│ ├── drawable-hdpi
│ ├── ic_expand_web.png
│ ├── ic_util_color.png
│ ├── ic_util_drawable.png
│ ├── ic_widget_button.png
│ ├── ic_widget_dialog.png
│ ├── ic_widget_flowlayout.png
│ ├── ic_widget_layout.png
│ ├── ic_widget_loading.png
│ ├── ic_widget_picker_view.png
│ ├── ic_widget_spinner.png
│ ├── ic_widget_statelayout.png
│ ├── ic_widget_titlebar.png
│ ├── icon_tabbar_component.png
│ ├── icon_tabbar_component_selected.png
│ ├── icon_tabbar_expand.png
│ ├── icon_tabbar_expand_selected.png
│ ├── icon_tabbar_util.png
│ └── icon_tabbar_util_selected.png
│ ├── drawable-xhdpi
│ ├── btn_add_food.png
│ ├── ic_back_white.webp
│ ├── page1.webp
│ ├── page2.webp
│ ├── page3.webp
│ ├── tab_courseware_normal.png
│ ├── tab_courseware_press.png
│ ├── tab_me_normal.png
│ └── tab_me_press.png
│ ├── drawable
│ ├── ic_back_dark.xml
│ ├── ic_checked_right.xml
│ ├── ic_launcher_background.xml
│ ├── ic_well_chosen.xml
│ ├── selector_icon_tabbar_component.xml
│ ├── selector_icon_tabbar_expand.xml
│ ├── selector_icon_tabbar_util.xml
│ ├── tab_color.xml
│ ├── tab_me.xml
│ ├── tab_permission.xml
│ └── white_radius.xml
│ ├── mipmap
│ └── ic_launcher.webp
│ ├── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ ├── styles.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle
├── core
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── brick
│ │ ├── BrickPreview.kt
│ │ ├── BrickUI.kt
│ │ ├── JavaDrawableUtils.java
│ │ ├── cache
│ │ └── DrawableCache.kt
│ │ ├── drawable
│ │ ├── OvalClipDrawable.kt
│ │ └── RectClipDrawable.kt
│ │ ├── init
│ │ ├── BrickUIInitializer.kt
│ │ └── ViewInit.kt
│ │ ├── ktx
│ │ ├── layout
│ │ │ ├── CollapsingToolbarLayout.kt
│ │ │ ├── ConstraintLayoutKTX.kt
│ │ │ ├── CoordinatorLayout.kt
│ │ │ ├── FlexboxLayoutKTX.kt
│ │ │ ├── FrameLayoutKTX.kt
│ │ │ ├── GridLayoutKTX.kt
│ │ │ ├── LayoutKTX.kt
│ │ │ ├── LinearLayoutKTX.kt
│ │ │ ├── NestedScrollView.kt
│ │ │ ├── RelativeLayoutKTX.kt
│ │ │ ├── TabLayoutKTX.kt
│ │ │ └── Toolbar.kt
│ │ ├── util
│ │ │ ├── ActivityKTX.kt
│ │ │ ├── AnimatorKTX.kt
│ │ │ ├── CommonKTX.kt
│ │ │ ├── DrawableKTX.kt
│ │ │ ├── ResourceKTX.kt
│ │ │ ├── SpanKTX.kt
│ │ │ └── ViewClipKTX.kt
│ │ └── widget
│ │ │ ├── FragmentKTX.kt
│ │ │ ├── FragmentPagerKTX.kt
│ │ │ ├── NestedScrollableKTX.kt
│ │ │ ├── RecyclerViewKTX.kt
│ │ │ ├── SimpleRecyclerViewKTX.kt
│ │ │ ├── SimpleStatelessRecyclerViewKTX.kt
│ │ │ ├── ViewKTX.kt
│ │ │ └── ViewPagerKTX.kt
│ │ ├── params
│ │ ├── CollapseMode.java
│ │ ├── CompoundDrawables.kt
│ │ ├── CornerRadius.kt
│ │ ├── EdgeInsets.kt
│ │ ├── RecyclerItemData.kt
│ │ └── Shadow.kt
│ │ ├── span
│ │ └── CenterAlignImageSpan.java
│ │ └── view
│ │ ├── BrickFragment.kt
│ │ ├── ConstraintHelper.kt
│ │ ├── DividerDecoration.kt
│ │ ├── FixDurationScroller.kt
│ │ ├── GridSpaceDecoration.kt
│ │ ├── LimitLinesFlexboxLayout.kt
│ │ ├── NestedScrollableHost.kt
│ │ ├── ShadowLayout.kt
│ │ └── WindowInsetsFrameLayout.kt
│ └── res
│ └── animator
│ └── scale_with_alpha.xml
├── dependencies.gradle
├── doc
├── BrickUI.md
├── BrickUIPreview.png
├── CvteCall.png
├── QRCodeDemo.png
├── RecylerView.md
├── courseLive.png
├── demo_page.png
├── en.png
└── seewoScan.png
├── glide
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── seewo
│ └── brick
│ ├── glide
│ └── exception
│ │ └── GlideBlurTransformation.kt
│ └── ktx
│ └── GlideKTX.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradles
├── jfrog-push.gradle
├── jitpack-push.gradle
└── utils.gradle
├── gradlew
├── gradlew.bat
├── live
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── seewo
│ └── brick
│ ├── ktx
│ ├── LifecycleKTX.kt
│ ├── LiveBrickViewKTX.kt
│ ├── LiveDataKTX.kt
│ ├── LiveGlideKTX.kt
│ ├── LiveLayoutKTX.kt
│ ├── LiveLoopPager.kt
│ ├── LiveRecyclerViewKTX.kt
│ ├── LiveResourceKTX.kt
│ ├── LiveSmartRefreshKTX.kt
│ ├── LiveViewKTX.kt
│ └── LiveViewPager.kt
│ └── live
│ └── params
│ └── StaticData.kt
├── loop-pager
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── seewo
│ │ └── brick
│ │ ├── indicator
│ │ ├── BaseCircleIndicator.kt
│ │ ├── CircleIndicator.kt
│ │ └── CircleIndicator3.kt
│ │ ├── ktx
│ │ ├── IndicatorKTX.kt
│ │ ├── InternalKTX.kt
│ │ └── LoopPagerKTX.kt
│ │ └── pager
│ │ ├── LoopPagerAdapterWrapper.kt
│ │ └── LoopViewPager.kt
│ └── res
│ └── animator
│ └── scale_with_alpha.xml
├── settings.gradle
├── smart-refresh
├── .gitignore
├── build.gradle
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── seewo
│ └── brick
│ └── ktx
│ └── SmartRefreshKTX.kt
└── versions.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /.idea/
17 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change LOG
2 |
3 | ### 0.2.43
4 |
5 | - [feature] TabLayout增加fixedItemWidth参数:当tabMode为MODE_SCROLLABLE时,设置每个Tab的固定宽度(如果不设置,可能控件自带奇怪的padding)
6 | - [fix] liveTabLayout的data参数改为LiveData类型
7 | - [fix] 修复设置阴影的blur较小,offset较大时,内容被裁剪的问题
8 |
9 | ### 0.2.40
10 |
11 | - [fix] 修复loopPager嵌套在RecyclerView或ViewPager中时,进行自动动画翻页时的几个经典bug,如翻页动画丢失,动画卡在一半
12 | - [fix] 修复liveLoopPager闪退问题,liveLoopPager的duration改为LiveData类型
13 |
14 | ### 0.2.36
15 |
16 | - [feature] 为DrawableKTX增加简单的缓存机制,调用方需要设置cacheKey以使其生效,并需要保证cacheKey不变且唯一
17 |
18 | ### 0.2.35
19 |
20 | - [improve] loop-pager在onStop时,停止轮播,onStart恢复轮播
21 |
22 | ### 0.2.34
23 |
24 | - [feature] loop-pager提供live支持
25 | - [feature] loop-pager支持设置滚动动画时长
26 | - [feature] glideImage提供live支持
27 |
28 | ### 0.2.31
29 |
30 | - [feature] 添加nestedScrollableChild,帮助解决ViewPager2等的嵌套导致的滑动冲突问题
31 | - [improve] 为viewPager添加以Context为接收者的函数
32 |
33 | ### 0.2.30
34 |
35 | - [feature] 添加brick函数用于嵌入普通View,废弃view函数
36 | - [improve] 为ViewKTX中的函数均添加以Context为接收者的函数
37 | - [feature] 封装loop-pager组件,提供轮播图和pager指示器的实现 (基于[CircleIndicator](https://github.com/ongakuer/CircleIndicator)实现)
38 |
39 | ### 0.2.23
40 |
41 | - improve: 对于LiveData添加了toVisibility()扩展函数,inverse扩展属性,并重载了not操作符
42 |
43 | ### 0.2.22
44 |
45 | - improve: 为资源相关扩展函数添加类型注解
46 | - improve: RecyclerView,SmartRefresh等添加Receiver为Context的扩展函数
47 |
48 | ### 0.2.21
49 |
50 | - improve: runAnimator和live组件允许传入LifecycleOwner,避免在Fragment使用时造成内存泄露
51 |
52 | ### 0.2.20
53 |
54 | - improve: runAnimator增加生命周期监听并自动取消动画
55 |
56 | ### 0.2.19
57 |
58 | - feature: 提供更易调用的`LiveData.bind(context, block)`和`LiveData.bindNotNull(context, block)`方法,方便开发者绑定LiveData到View。
59 | - improve: 优化`LiveData.bind(context, block)`和`LiveData.bindNotNull(context, block)`方法的实现,如果value无变化,不会重复调用`block`方法
60 | > **注意**,以上两个方法所接收的Context必须是FragmentActivity一类的`LifecycleOwner`,否则绑定无法生效
61 |
62 | ### 0.2.17
63 |
64 | - feature: 统一为ViewGroup构造的View添加`margin`参数
65 |
66 | ### 0.2.16
67 |
68 | - Improve: 移除`Fragment.fragmentPager()`方法,改用参数`parentFragment`参数来实现此功能
69 |
70 | ### 0.2.15
71 |
72 | - Improve: `smartRefresh`提到单独module:com.github.robin8yeung.BrickUI:brick-ui-smart-refresh。**(注意:用到smartRefresh的话必须引入此依赖)**
73 | - feature: 添加`Fragment.fragmentPager()`方法,来构造基于Fragment生命周期的fragmentPager
74 | - feature: 统一增加`foreground`属性(系统版本23以上才支持)
75 | - feature: 提供`livePlaceHolder()`构造占位View
76 |
77 | ### 0.2.14
78 |
79 | - Improve: 为LiveData增加combine扩展函数,方便合并2个LiveData的值来处理UI状态
80 |
81 | ### 0.2.13
82 |
83 | - Improve: 允许RecyclerView类控件接受非RecyclerItemData类型的数据,但仍然强烈建议传入RecyclerItemData类型的数据,以使用DiffUtil来更新RecyclerView
84 |
85 | ### 0.2.12
86 |
87 | - New: 增加CoordinatorLayout相关的支持
88 |
89 | ### 0.2.11
90 |
91 | - New: 增加TabLayout相关的支持
92 |
93 | ### 0.2.7
94 |
95 | - Improve: 补充LiveLayoutKTX中几个Context的扩展布局函数
96 |
97 | ### 0.2.6
98 |
99 | - Improve: 对几种Widget引入泛型,避免丢类型
100 |
101 | ### 0.2.5
102 |
103 | - New: 增加sourceJar打包,避免使用时无法链接到源码
104 |
105 | ### 0.2.1
106 |
107 | - New: 首次正式发布版本
108 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | applicationId "com.seewo.brick.app"
11 | minSdk 21
12 | targetSdk 32
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled false
21 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 | compileOptions {
25 | sourceCompatibility JavaVersion.VERSION_1_8
26 | targetCompatibility JavaVersion.VERSION_1_8
27 | }
28 | kotlinOptions {
29 | jvmTarget = '1.8'
30 | }
31 | buildFeatures {
32 | viewBinding true
33 | }
34 | }
35 |
36 | dependencies {
37 | implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
38 | // implementation(name: 'andnext_markdown-debug', ext: 'aar')
39 | implementation rootProject.ext.deps.kotlin.coroutines.core
40 | implementation rootProject.ext.deps.kotlin.coroutines.android
41 |
42 | implementation rootProject.ext.deps.android.appcompat
43 | implementation rootProject.ext.deps.android.material
44 | implementation rootProject.ext.deps.android.constraintlayout
45 |
46 | implementation rootProject.ext.deps.toast
47 |
48 | // KTX
49 | implementation rootProject.ext.deps.ktx.core
50 | implementation rootProject.ext.deps.ktx.collection
51 | implementation rootProject.ext.deps.ktx.fragment
52 | implementation project(':core')
53 | implementation project(':live')
54 | implementation project(':smart-refresh')
55 | implementation project(':loop-pager')
56 | implementation project(':glide')
57 | implementation rootProject.ext.deps.glide
58 |
59 | implementation rootProject.ext.deps.android.flexbox
60 |
61 | implementation rootProject.ext.deps.smart_refresh_new.core
62 | implementation rootProject.ext.deps.smart_refresh_new.classics_header
63 | implementation rootProject.ext.deps.smart_refresh_new.classics_footer
64 | }
--------------------------------------------------------------------------------
/app/libs/andnext_markdown-debug.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/libs/andnext_markdown-debug.aar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
20 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/App.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app
2 |
3 | import android.app.Application
4 | import com.hjq.toast.ToastUtils
5 |
6 | class App: Application() {
7 | override fun onCreate() {
8 | super.onCreate()
9 | ToastUtils.init(this)
10 | }
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/ComponentFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.seewo.brick.BrickPreview
6 | import com.seewo.brick.app.R
7 | import com.seewo.brick.app.component.coordinator.CoordinatorLayoutActivity1
8 | import com.seewo.brick.app.component.coordinator.CoordinatorLayoutActivity2
9 | import com.seewo.brick.app.component.extra.ExtraComponentActivity
10 | import com.seewo.brick.app.component.layout.LayoutActivity
11 | import com.seewo.brick.app.component.list.list.ListActivity
12 | import com.seewo.brick.app.component.list.simple.SimpleListActivity
13 | import com.seewo.brick.app.component.pager.PagerActivity
14 | import com.seewo.brick.app.main.MainItemBean
15 | import com.seewo.brick.app.main.mainFragmentList
16 | import com.seewo.brick.ktx.drawable
17 | import com.seewo.brick.ktx.startActivity
18 | import com.seewo.brick.ktx.view
19 |
20 | class PreviewComponentFragment(context: Context, attrs: AttributeSet? = null) :
21 | BrickPreview(context, attrs) {
22 |
23 | override fun preview(context: Context) {
24 | view {
25 | context.ComponentPage()
26 | }
27 | }
28 | }
29 |
30 | fun Context.ComponentPage() = mainFragmentList(
31 | listOf(
32 | MainItemBean("控件与布局", R.drawable.ic_widget_layout.drawable) {
33 | startActivity()
34 | },
35 | MainItemBean("吸顶布局", R.drawable.ic_widget_titlebar.drawable) {
36 | startActivity()
37 | },
38 | MainItemBean("折叠布局", R.drawable.ic_widget_titlebar.drawable) {
39 | startActivity()
40 | },
41 | MainItemBean("增强控件", R.drawable.icon_tabbar_expand_selected.drawable) {
42 | startActivity()
43 | },
44 | MainItemBean("静态列表", R.drawable.ic_widget_flowlayout.drawable) {
45 | startActivity()
46 | },
47 | MainItemBean("动态列表", R.drawable.ic_widget_picker_view.drawable) {
48 | startActivity()
49 | },
50 | MainItemBean("分页", R.drawable.ic_widget_statelayout.drawable) {
51 | startActivity()
52 | },
53 | )
54 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/extra/ExtraComponentActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.extra
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.component.extra.page.EmbededPage
6 | import com.seewo.brick.app.component.extra.page.GlidePage
7 | import com.seewo.brick.app.component.extra.page.SmartRefreshPage
8 | import com.seewo.brick.app.widget.multiTabViewPager
9 | import com.seewo.brick.ktx.MATCH_PARENT
10 | import com.seewo.brick.ktx.frameLayout
11 | import com.seewo.brick.ktx.setStatusBarTransparent
12 |
13 | class ExtraComponentActivity : AppCompatActivity() {
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setStatusBarTransparent(true)
18 | setContentView(multiTabViewPager(
19 | data = listOf(
20 | "图片加载",
21 | "下拉加载",
22 | "原生控件嵌入",
23 | ),
24 | ) { _, index ->
25 | when (index) {
26 | 0 -> GlidePage()
27 | 1 -> SmartRefreshPage()
28 | 2 -> EmbededPage()
29 | else -> frameLayout(
30 | MATCH_PARENT, MATCH_PARENT,
31 | )
32 | }
33 | })
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/extra/page/EmbededPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.extra.page
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.LinearLayout
6 | import com.seewo.brick.BrickPreview
7 | import com.seewo.brick.app.widget.Markdown
8 | import com.seewo.brick.ktx.MATCH_PARENT
9 | import com.seewo.brick.ktx.column
10 | import com.seewo.brick.ktx.expand
11 | import com.seewo.brick.ktx.view
12 |
13 | private class EmbededPage(context: Context, attrs: AttributeSet? = null) :
14 | BrickPreview(context, attrs) {
15 |
16 | override fun preview(context: Context) {
17 | view {
18 | context.EmbededPage()
19 | }
20 | }
21 | }
22 |
23 | fun Context.EmbededPage() = column(
24 | MATCH_PARENT, MATCH_PARENT,
25 | ) {
26 | ShowMarkDown()
27 | }
28 |
29 | private fun LinearLayout.ShowMarkDown() {
30 | expand {
31 | Markdown(
32 | """
33 | ## 代码展示
34 |
35 | 虽然BrickUI封装了一些常用的控件,和一些好用的第三方控件,但不可能对所有控件都进行封装,而且这样做意义不大。
36 | 由于BrickUI本身就是基于View体系实现的,把第三方控件嵌入到BrickUI中并非难事。
37 | 当前你所看到的Markdown文档就是用第三方控件来展示的,实现如下:
38 |
39 | ```kotlin
40 | private fun LinearLayout.ShowMarkDown() {
41 | expand {
42 | Markdown(
43 | ""${'"'}
44 | ...
45 | 这里是 Markdown 文档
46 | ...
47 | ""${'"'}.trimIndent()
48 | )
49 | }
50 | }
51 |
52 | fun ViewGroup.Markdown(
53 | text: String
54 | ): View {
55 | if (isInEditMode) return placeholder() // 避免预览模式报错
56 | return view {
57 | // 第三方控件:MarkdownWebView
58 | MarkdownWebView(context).apply {
59 | // 初始化宽高
60 | init(MATCH_PARENT, MATCH_PARENT)
61 | setText(text)
62 | }
63 | }
64 | }
65 | ```
66 | """.trimIndent()
67 | )
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/extra/page/GlidePage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.extra.page
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.LinearLayout
6 | import com.bumptech.glide.load.resource.bitmap.CenterCrop
7 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners
8 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
9 | import com.bumptech.glide.request.RequestOptions
10 | import com.hjq.toast.ToastUtils
11 | import com.seewo.brick.BrickPreview
12 | import com.seewo.brick.app.widget.Markdown
13 | import com.seewo.brick.ktx.*
14 | import com.seewo.brick.params.EdgeInsets
15 |
16 | private class GlidePage(context: Context, attrs: AttributeSet? = null) :
17 | BrickPreview(context, attrs) {
18 |
19 | override fun preview(context: Context) {
20 | view {
21 | context.GlidePage()
22 | }
23 | }
24 | }
25 |
26 | fun Context.GlidePage() = column(
27 | MATCH_PARENT, MATCH_PARENT,
28 | ) {
29 | networkImages()
30 |
31 | ShowMarkDown()
32 | }
33 |
34 | private fun LinearLayout.networkImages() {
35 | row(
36 | padding = EdgeInsets.symmetric(4.dp, 16.dp)
37 | ) {
38 | // 简单加载图片
39 | glideImage(
40 | urlOrPath = "https://easinote.seewo.com/statics/modules/themes/images/index/1x/qrode_ebf6c6e.png",
41 | ) {
42 | // 可选择imageView,也可选择liveImage
43 | imageView(84.dp, 84.dp)
44 | }
45 | // 自定义各种参数和回调
46 | glideImage(
47 | urlOrPath = "https://img0.baidu.com/it/u=3995530121,45712565&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313",
48 | transition = DrawableTransitionOptions.withCrossFade(),
49 | requestOptions = RequestOptions()
50 | .transform(
51 | CenterCrop(), RoundedCorners(4.dp),
52 | ),
53 | onLoadFailed = {
54 | ToastUtils.show("图片加载异常")
55 | },
56 | onResourceReady = {
57 | ToastUtils.show("图片加载完成")
58 | }
59 | ) {
60 | imageView(150.dp, 84.dp)
61 | }
62 | }
63 | }
64 |
65 | private fun LinearLayout.ShowMarkDown() {
66 | expand {
67 | Markdown(
68 | """
69 | ## 代码展示
70 |
71 | 主要提供了 glideImage、glideGif 2个函数来修饰ImageView,用于执行网络图片或本地图片加载,提供了Glide框架的相关能力
72 |
73 | ```kotlin
74 | private fun LinearLayout.networkImages() {
75 | row(
76 | padding = EdgeInsets.symmetric(4.dp, 16.dp)
77 | ) {
78 | // 简单加载图片
79 | glideImage(
80 | urlOrPath = "https://easinote.seewo.com/statics/modules/themes/images/index/1x/qrode_ebf6c6e.png",
81 | ) {
82 | // 可选择imageView,也可选择liveImage
83 | imageView(84.dp, 84.dp)
84 | }
85 | // 自定义各种参数和回调
86 | glideImage(
87 | urlOrPath = "https://img0.baidu.com/it/u=3995530121,45712565&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313",
88 | transition = DrawableTransitionOptions.withCrossFade(),
89 | requestOptions = RequestOptions()
90 | .transform(
91 | CenterCrop(), RoundedCorners(4.dp),
92 | ),
93 | onLoadFailed = {
94 | ToastUtils.show("图片加载异常")
95 | },
96 | onResourceReady = {
97 | ToastUtils.show("图片加载完成")
98 | }
99 | ) {
100 | imageView(150.dp, 84.dp)
101 | }
102 | }
103 | }
104 | ```
105 | """.trimIndent()
106 | )
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/layout/LayoutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.layout
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.component.layout.page.ColumnPage
6 | import com.seewo.brick.app.component.layout.page.ConstraintPage
7 | import com.seewo.brick.app.component.layout.page.FlexboxPage
8 | import com.seewo.brick.app.component.layout.page.RelativePage
9 | import com.seewo.brick.app.component.layout.page.RowPage
10 | import com.seewo.brick.app.widget.multiTabViewPager
11 | import com.seewo.brick.ktx.MATCH_PARENT
12 | import com.seewo.brick.ktx.frameLayout
13 | import com.seewo.brick.ktx.setStatusBarTransparent
14 |
15 | class LayoutActivity : AppCompatActivity() {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setStatusBarTransparent(true)
20 | setContentView(multiTabViewPager(
21 | data = listOf(
22 | "行布局",
23 | "列布局",
24 | "相对布局",
25 | "约束布局",
26 | "Flexbox布局",
27 | ),
28 | viewPagerBuilder = { _, index ->
29 | when (index) {
30 | 0 -> RowPage()
31 | 1 -> ColumnPage()
32 | 2 -> RelativePage()
33 | 3 -> ConstraintPage()
34 | 4 -> FlexboxPage()
35 | else -> frameLayout(
36 | MATCH_PARENT, MATCH_PARENT,
37 | )
38 | }
39 | }
40 | ))
41 | }
42 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/layout/page/FlexboxPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.layout.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.widget.LinearLayout
7 | import com.seewo.brick.BrickPreview
8 | import com.seewo.brick.app.widget.Markdown
9 | import com.seewo.brick.ktx.MATCH_PARENT
10 | import com.seewo.brick.ktx.column
11 | import com.seewo.brick.ktx.dp
12 | import com.seewo.brick.ktx.expand
13 | import com.seewo.brick.ktx.flexboxLayout
14 | import com.seewo.brick.ktx.rectDrawable
15 | import com.seewo.brick.ktx.textView
16 | import com.seewo.brick.ktx.view
17 | import com.seewo.brick.ktx.withAlpha
18 | import com.seewo.brick.params.CornerRadius
19 | import com.seewo.brick.params.EdgeInsets
20 | import com.seewo.brick.view.LimitLinesFlexboxLayout
21 |
22 | class FlexboxPage(context: Context, attrs: AttributeSet? = null) :
23 | BrickPreview(context, attrs) {
24 |
25 | override fun preview(context: Context) {
26 | view {
27 | context.FlexboxPage()
28 | }
29 | }
30 | }
31 |
32 | fun Context.FlexboxPage() = column(
33 | MATCH_PARENT, MATCH_PARENT,
34 | ) {
35 | Chips()
36 | ShowMarkDown()
37 | }
38 |
39 | private fun LinearLayout.Chips() {
40 | // flexboxLayout 用于线性展示控件,并在控件不够时可以换行
41 | // 需要引入FlexboxLayout的依赖 com.google.android.flexbox:flexbox
42 | flexboxLayout(
43 | MATCH_PARENT,
44 | padding = EdgeInsets.symmetric(8.dp, 16.dp)
45 | ) {
46 | repeat(10) {
47 | Chip(it)
48 | }
49 | }
50 | }
51 |
52 | private fun LimitLinesFlexboxLayout.Chip(it: Int) {
53 | textView(
54 | background = rectDrawable(
55 | corners = CornerRadius.all(4.dp),
56 | fillColor = Color.GRAY.withAlpha(0.7f),
57 | ),
58 | margin = EdgeInsets.all(4.dp),
59 | padding = EdgeInsets.symmetric(2.dp, 6.dp),
60 | text = "TAG $it",
61 | textColor = Color.WHITE,
62 | textSize = 12.dp,
63 | )
64 | }
65 |
66 | private fun LinearLayout.ShowMarkDown() {
67 | expand {
68 | Markdown(
69 | """
70 | ## 代码展示
71 |
72 | 需要引入FlexboxLayout的依赖 com.google.android.flexbox:flexbox
73 |
74 | ```kotlin
75 | private fun LinearLayout.Chips() {
76 | // flexboxLayout 用于线性展示控件,并在控件不够时可以换行
77 | flexboxLayout(
78 | MATCH_PARENT,
79 | padding = EdgeInsets.symmetric(8.dp, 16.dp)
80 | ) {
81 | repeat(10) {
82 | Chip(it)
83 | }
84 | }
85 | }
86 |
87 | private fun LimitLinesFlexboxLayout.Chip(it: Int) {
88 | textView(
89 | background = rectDrawable(
90 | corners = CornerRadius.all(4.dp),
91 | fillColor = Color.GRAY.withAlpha(0.7f),
92 | ),
93 | margin = EdgeInsets.all(4.dp),
94 | padding = EdgeInsets.symmetric(2.dp, 6.dp),
95 | text = "TAG ${'$'}it",
96 | textColor = Color.WHITE,
97 | textSize = 12.dp,
98 | )
99 | }
100 | ```
101 | """.trimIndent()
102 | )
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/layout/page/RelativePage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.layout.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.widget.LinearLayout
7 | import android.widget.RelativeLayout
8 | import com.seewo.brick.BrickPreview
9 | import com.seewo.brick.app.R
10 | import com.seewo.brick.app.widget.Markdown
11 | import com.seewo.brick.ktx.*
12 | import com.seewo.brick.params.EdgeInsets
13 |
14 | class RelativePage(context: Context, attrs: AttributeSet? = null) :
15 | BrickPreview(context, attrs) {
16 |
17 | override fun preview(context: Context) {
18 | view {
19 | context.RelativePage()
20 | }
21 | }
22 | }
23 |
24 | fun Context.RelativePage() = column(
25 | MATCH_PARENT, MATCH_PARENT,
26 | animateLayoutChanges = true,
27 | ) {
28 | IconWithBadge()
29 | ShowMarkDown()
30 | }
31 |
32 | private fun LinearLayout.IconWithBadge() {
33 | relativeLayout(
34 | MATCH_PARENT,
35 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
36 | ) {
37 | // icon在布局内居中
38 | layoutParams(
39 | rules = {
40 | addRule(RelativeLayout.CENTER_IN_PARENT)
41 | },
42 | ) {
43 | // 圆角裁剪
44 | roundRectClip(radius = 4.dp) {
45 | // icon,这里id取得比较随意,正式使用,建议把id定义在ids.xml中
46 | imageView(
47 | 48.dp, 48.dp,
48 | id = 0x1234,
49 | drawable = R.mipmap.ic_launcher.drawable,
50 | )
51 | }
52 | }
53 | // 红点布局与icon的右侧对齐
54 | layoutParams(
55 | rules = {
56 | addRule(RelativeLayout.ALIGN_END, 0x1234)
57 | },
58 | margins = EdgeInsets.only(end = (-4).dp, top = (-4).dp)
59 | ) {
60 | // 随便用个占位符作为红点
61 | placeholder(
62 | 8.dp,
63 | 8.dp,
64 | background = ovalDrawable(fillColor = Color.RED)
65 | )
66 | }
67 | }.apply {
68 | // 避免布局padding裁剪红点
69 | clipToOutline = false
70 | clipToPadding = false
71 | }
72 | }
73 |
74 | private fun LinearLayout.ShowMarkDown() {
75 | expand {
76 | Markdown(
77 | """
78 | ## 代码展示
79 |
80 | ```kotlin
81 | private fun LinearLayout.IconWithBadge() {
82 | relativeLayout(
83 | MATCH_PARENT,
84 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
85 | ) {
86 | // icon在布局内居中
87 | layoutParams(
88 | rules = {
89 | addRule(RelativeLayout.CENTER_IN_PARENT)
90 | },
91 | ) {
92 | // 圆角裁剪
93 | roundRectClip(radius = 4.dp) {
94 | // icon,这里id取得比较随意,正式使用,建议把id定义在ids.xml中
95 | imageView(
96 | 48.dp, 48.dp,
97 | id = 0x1234,
98 | drawable = R.mipmap.ic_launcher.drawable,
99 | )
100 | }
101 | }
102 | // 红点布局与icon的右侧对齐
103 | layoutParams(
104 | rules = {
105 | addRule(RelativeLayout.ALIGN_END, 0x1234)
106 | },
107 | margins = EdgeInsets.only(end = (-4).dp, top = (-4).dp)
108 | ) {
109 | // 随便用个占位符作为红点
110 | placeholder(
111 | 8.dp,
112 | 8.dp,
113 | background = ovalDrawable(fillColor = Color.RED)
114 | )
115 | }
116 | }.apply {
117 | // 避免布局padding裁剪红点
118 | clipToOutline = false
119 | clipToPadding = false
120 | }
121 | }
122 | ```
123 | """.trimIndent()
124 | )
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/list/ListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.list
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.component.list.list.page.ComplexStatefulListPage
6 | import com.seewo.brick.app.component.list.list.page.StatefulListPage
7 | import com.seewo.brick.app.widget.multiTabViewPager
8 | import com.seewo.brick.ktx.MATCH_PARENT
9 | import com.seewo.brick.ktx.frameLayout
10 | import com.seewo.brick.ktx.setStatusBarTransparent
11 |
12 | class ListActivity : AppCompatActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setStatusBarTransparent(true)
17 | setContentView(multiTabViewPager(
18 | data = listOf(
19 | "动态列表",
20 | "动态列表(复杂实现)",
21 | ),
22 | viewPagerBuilder = { _, index ->
23 | when (index) {
24 | 0 -> StatefulListPage()
25 | 1 -> ComplexStatefulListPage()
26 | else -> frameLayout(
27 | MATCH_PARENT, MATCH_PARENT,
28 | )
29 | }
30 | }
31 | ))
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/simple/SimpleListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.simple
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.component.list.simple.page.GridListPage
6 | import com.seewo.brick.app.component.list.simple.page.HorizontalListPage
7 | import com.seewo.brick.app.component.list.simple.page.ScrollViewPage
8 | import com.seewo.brick.app.component.list.simple.page.VerticalListPage
9 | import com.seewo.brick.app.widget.multiTabViewPager
10 | import com.seewo.brick.ktx.MATCH_PARENT
11 | import com.seewo.brick.ktx.frameLayout
12 | import com.seewo.brick.ktx.setStatusBarTransparent
13 |
14 | class SimpleListActivity : AppCompatActivity() {
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setStatusBarTransparent(true)
19 | setContentView(multiTabViewPager(
20 | data = listOf(
21 | "纵向列表",
22 | "横向列表",
23 | "方阵列表",
24 | "页面滚动",
25 | ),
26 | viewPagerBuilder = { _, index ->
27 | when (index) {
28 | 0 -> VerticalListPage()
29 | 1 -> HorizontalListPage()
30 | 2 -> GridListPage()
31 | 3 -> ScrollViewPage()
32 | else -> frameLayout(
33 | MATCH_PARENT, MATCH_PARENT,
34 | )
35 | }
36 | }
37 | ))
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/simple/page/GridListPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.simple.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.view.Gravity
7 | import android.widget.LinearLayout
8 | import androidx.recyclerview.widget.GridLayoutManager
9 | import com.seewo.brick.BrickPreview
10 | import com.seewo.brick.app.R
11 | import com.seewo.brick.app.widget.Markdown
12 | import com.seewo.brick.ktx.*
13 | import com.seewo.brick.params.EdgeInsets
14 |
15 | private class GridListPage(context: Context, attrs: AttributeSet? = null) :
16 | BrickPreview(context, attrs) {
17 |
18 | override fun preview(context: Context) {
19 | view {
20 | context.GridListPage()
21 | }
22 | }
23 | }
24 |
25 | fun Context.GridListPage() = column(
26 | MATCH_PARENT, MATCH_PARENT,
27 | ) {
28 | SimpleList()
29 | ShowMarkDown()
30 | }
31 |
32 | private fun LinearLayout.SimpleList() {
33 | simpleStatelessRecyclerView(
34 | MATCH_PARENT, WRAP_CONTENT,
35 | // 列表数据
36 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
37 | // 设置LayoutManager,每行4列
38 | layoutManager = GridLayoutManager(context, 4),
39 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
40 | ) { data, index ->
41 | // 构造每一项的控件,可以根据不同的item构建不同的控件
42 | val item = data[index]
43 | textView(
44 | MATCH_PARENT, 48.dp,
45 | text = "$item",
46 | // 单数为主题色,双数为黑色
47 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
48 | textSize = 14.dp,
49 | gravity = Gravity.CENTER,
50 | )
51 | }
52 | }
53 |
54 | private fun LinearLayout.ShowMarkDown() {
55 | expand {
56 | Markdown(
57 | """
58 | ## 代码展示
59 |
60 | 无状态简单列表,静态设置的简单列表,data为固定列表,不可修改
61 |
62 | ```kotlin
63 | private fun LinearLayout.simpleList() {
64 | simpleStatelessRecyclerView(
65 | MATCH_PARENT, WRAP_CONTENT,
66 | // 列表数据
67 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
68 | // 设置LayoutManager,每行4列
69 | layoutManager = GridLayoutManager(context, 4),
70 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
71 | ) { data, index ->
72 | // 构造每一项的控件,可以根据不同的item构建不同的控件
73 | val item = data[index]
74 | textView(
75 | MATCH_PARENT, 48.dp,
76 | text = "${'$'}item",
77 | // 单数为主题色,双数为黑色
78 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
79 | textSize = 14.dp,
80 | gravity = Gravity.CENTER,
81 | )
82 | }
83 | }
84 | ```
85 | """.trimIndent()
86 | )
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/simple/page/HorizontalListPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.simple.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.view.Gravity
7 | import android.widget.LinearLayout
8 | import androidx.recyclerview.widget.LinearLayoutManager
9 | import com.seewo.brick.BrickPreview
10 | import com.seewo.brick.app.R
11 | import com.seewo.brick.app.widget.Markdown
12 | import com.seewo.brick.ktx.*
13 | import com.seewo.brick.params.EdgeInsets
14 |
15 | private class HorizontalListPage(context: Context, attrs: AttributeSet? = null) :
16 | BrickPreview(context, attrs) {
17 |
18 | override fun preview(context: Context) {
19 | view {
20 | context.HorizontalListPage()
21 | }
22 | }
23 | }
24 |
25 | fun Context.HorizontalListPage() = column(
26 | MATCH_PARENT, MATCH_PARENT,
27 | ) {
28 | SimpleList()
29 | ShowMarkDown()
30 | }
31 |
32 | private fun LinearLayout.SimpleList() {
33 | simpleStatelessRecyclerView(
34 | MATCH_PARENT, WRAP_CONTENT,
35 | // 列表数据
36 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9),
37 | // 设置分割线
38 | itemDecoration = dividerDecoration(
39 | color = R.color.primary.color,
40 | orientation = LinearLayoutManager.HORIZONTAL,
41 | ),
42 | // 设置横向LayoutManager
43 | layoutManager = LinearLayoutManager(context).apply {
44 | orientation = LinearLayoutManager.HORIZONTAL
45 | },
46 | // 注意:由于默认ViewHolder不适合布局横向列表,这里需要自定义一个宽高结尾WRAP_CONTENT的帧布局
47 | viewHolderCreator = {
48 | frameLayout()
49 | },
50 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
51 | ) { data, index ->
52 | // 构造每一项的控件,可以根据不同的item构建不同的控件
53 | val item = data[index]
54 | textView(
55 | 48.dp, 32.dp,
56 | text = "$item",
57 | // 单数为主题色,双数为黑色
58 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
59 | textSize = 14.dp,
60 | gravity = Gravity.CENTER,
61 | )
62 | }
63 | }
64 |
65 | private fun LinearLayout.ShowMarkDown() {
66 | expand {
67 | Markdown(
68 | """
69 | ## 代码展示
70 |
71 | 无状态简单列表,静态设置的简单列表,data为固定列表,不可修改
72 |
73 | ```kotlin
74 | private fun LinearLayout.simpleList() {
75 | simpleStatelessRecyclerView(
76 | MATCH_PARENT, WRAP_CONTENT,
77 | // 列表数据
78 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9),
79 | // 设置分割线
80 | itemDecoration = dividerDecoration(
81 | color = R.color.primary.color,
82 | orientation = LinearLayoutManager.HORIZONTAL,
83 | ),
84 | // 设置横向LayoutManager
85 | layoutManager = LinearLayoutManager(context).apply {
86 | orientation = LinearLayoutManager.HORIZONTAL
87 | },
88 | // 注意:由于默认ViewHolder不适合布局横向列表,这里需要自定义一个宽高结尾WRAP_CONTENT的帧布局
89 | viewHolderCreator = {
90 | frameLayout()
91 | },
92 | padding = EdgeInsets.symmetric(vertical = 8.dp, horizontal = 16.dp)
93 | ) { data, index ->
94 | // 构造每一项的控件,可以根据不同的item构建不同的控件
95 | val item = data[index]
96 | textView(
97 | 48.dp, 32.dp,
98 | text = "${'$'}item",
99 | // 单数为主题色,双数为黑色
100 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
101 | textSize = 14.dp,
102 | gravity = Gravity.CENTER,
103 | )
104 | }
105 | }
106 | ```
107 | """.trimIndent()
108 | )
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/simple/page/ScrollViewPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.simple.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.view.Gravity
7 | import android.widget.LinearLayout
8 | import com.seewo.brick.BrickPreview
9 | import com.seewo.brick.app.R
10 | import com.seewo.brick.app.widget.Markdown
11 | import com.seewo.brick.ktx.*
12 | import com.seewo.brick.params.EdgeInsets
13 |
14 | private class ScrollViewPage(context: Context, attrs: AttributeSet? = null) :
15 | BrickPreview(context, attrs) {
16 |
17 | override fun preview(context: Context) {
18 | view {
19 | context.ScrollViewPage()
20 | }
21 | }
22 | }
23 |
24 | fun Context.ScrollViewPage() = column(
25 | MATCH_PARENT, MATCH_PARENT,
26 | ) {
27 | SimpleList()
28 | ShowMarkDown()
29 | }
30 |
31 | private fun LinearLayout.SimpleList() {
32 | scrollView(
33 | MATCH_PARENT, 100.dp,
34 | ) {
35 | column(
36 | MATCH_PARENT
37 | ) {
38 | repeat(50) {
39 | if (it != 0) {
40 | layoutParams(
41 | margins = EdgeInsets.symmetric(horizontal = 16.dp)
42 | ) {
43 | divider(
44 | background = R.color.primary.colorDrawable,
45 | )
46 | }
47 | }
48 | textView(
49 | MATCH_PARENT, 32.dp,
50 | text = "$it",
51 | // 单数为主题色,双数为黑色
52 | textColor = if (it % 2 == 0) Color.BLACK else R.color.primary.color,
53 | textSize = 14.dp,
54 | gravity = Gravity.CENTER,
55 | )
56 | }
57 | }
58 | }
59 | }
60 |
61 | private fun LinearLayout.ShowMarkDown() {
62 | expand {
63 | Markdown(
64 | """
65 | ## 代码展示
66 |
67 | 通过ScrollView实现页面可滚动
68 |
69 | ```kotlin
70 | private fun LinearLayout.simpleList() {
71 | scrollView(
72 | MATCH_PARENT, 100.dp,
73 | ) {
74 | column(
75 | MATCH_PARENT
76 | ) {
77 | repeat(50) {
78 | if (it != 0) {
79 | layoutParams(
80 | margins = EdgeInsets.symmetric(horizontal = 16.dp)
81 | ) {
82 | divider(
83 | background = R.color.primary.colorDrawable,
84 | )
85 | }
86 | }
87 | textView(
88 | MATCH_PARENT, 32.dp,
89 | text = "${'$'}it",
90 | // 单数为主题色,双数为黑色
91 | textColor = if (it % 2 == 0) Color.BLACK else R.color.primary.color,
92 | textSize = 14.dp,
93 | gravity = Gravity.CENTER,
94 | )
95 | }
96 | }
97 | }
98 | }
99 | ```
100 | """.trimIndent()
101 | )
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/list/simple/page/VerticalListPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.list.simple.page
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.util.AttributeSet
6 | import android.view.Gravity
7 | import android.widget.LinearLayout
8 | import com.seewo.brick.BrickPreview
9 | import com.seewo.brick.app.R
10 | import com.seewo.brick.app.widget.Markdown
11 | import com.seewo.brick.ktx.*
12 | import com.seewo.brick.params.EdgeInsets
13 |
14 | private class VerticalListPage(context: Context, attrs: AttributeSet? = null) :
15 | BrickPreview(context, attrs) {
16 |
17 | override fun preview(context: Context) {
18 | view {
19 | context.VerticalListPage()
20 | }
21 | }
22 | }
23 |
24 | fun Context.VerticalListPage() = column(
25 | MATCH_PARENT, MATCH_PARENT,
26 | ) {
27 | SimpleList()
28 | ShowMarkDown()
29 | }
30 |
31 | private fun LinearLayout.SimpleList() {
32 | simpleStatelessRecyclerView(
33 | MATCH_PARENT, 100.dp,
34 | // 列表数据
35 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9),
36 | // 设置分割线
37 | itemDecoration = dividerDecoration(
38 | color = R.color.primary.color,
39 | padding = EdgeInsets.only(bottom = 8.dp, start = 16.dp, end = 16.dp)
40 | ),
41 | ) { data, index ->
42 | // 构造每一项的控件,可以根据不同的item构建不同的控件
43 | val item = data[index]
44 | textView(
45 | MATCH_PARENT, 32.dp,
46 | text = "$item",
47 | // 单数为主题色,双数为黑色
48 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
49 | textSize = 14.dp,
50 | gravity = Gravity.CENTER,
51 | )
52 | }
53 | }
54 |
55 | private fun LinearLayout.ShowMarkDown() {
56 | expand {
57 | Markdown(
58 | """
59 | ## 代码展示
60 |
61 | 无状态简单列表,静态设置的简单列表,data为固定列表,不可修改
62 |
63 | ```kotlin
64 | private fun LinearLayout.simpleList() {
65 | simpleStatelessRecyclerView(
66 | MATCH_PARENT, 100.dp,
67 | // 列表数据
68 | data = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9),
69 | // 设置分割线
70 | itemDecoration = dividerDecoration(
71 | color = R.color.primary.color,
72 | padding = EdgeInsets.only(bottom = 8.dp, start = 16.dp, end = 16.dp)
73 | ),
74 | ) { data, index ->
75 | // 构造每一项的控件,可以根据不同的item构建不同的控件
76 | val item = data[index]
77 | textView(
78 | MATCH_PARENT, 32.dp,
79 | text = "${'$'}item",
80 | // 单数为主题色,双数为黑色
81 | textColor = if (item % 2 == 0) Color.BLACK else R.color.primary.color,
82 | textSize = 14.dp,
83 | gravity = Gravity.CENTER,
84 | )
85 | }
86 | }
87 | ```
88 | """.trimIndent()
89 | )
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/pager/PagerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.pager
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.component.pager.page.FragmentPagerPage
6 | import com.seewo.brick.app.component.pager.page.LoopViewPagerPage
7 | import com.seewo.brick.app.component.pager.page.TabLayoutViewPagerPage
8 | import com.seewo.brick.app.component.pager.page.ViewPagerPage
9 | import com.seewo.brick.app.widget.multiTabViewPager
10 | import com.seewo.brick.ktx.MATCH_PARENT
11 | import com.seewo.brick.ktx.frameLayout
12 | import com.seewo.brick.ktx.setStatusBarTransparent
13 |
14 | class PagerActivity : AppCompatActivity() {
15 |
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setStatusBarTransparent(true)
19 | setContentView(multiTabViewPager(
20 | data = listOf(
21 | "轮播图",
22 | "TabLayout分页切换",
23 | "分页切换",
24 | "Fragment分页切换",
25 | ),
26 | viewPagerBuilder = { _, index ->
27 | when (index) {
28 | 0 -> LoopViewPagerPage()
29 | 1 -> TabLayoutViewPagerPage()
30 | 2 -> ViewPagerPage()
31 | 3 -> FragmentPagerPage()
32 | else -> frameLayout(
33 | MATCH_PARENT, MATCH_PARENT,
34 | )
35 | }
36 | }
37 | ))
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/component/pager/page/LoopViewPagerPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.component.pager.page
2 |
3 |
4 | import android.content.Context
5 | import android.util.AttributeSet
6 | import android.util.Log
7 | import android.view.Gravity
8 | import android.widget.ImageView
9 | import android.widget.LinearLayout
10 | import com.seewo.brick.BrickPreview
11 | import com.seewo.brick.app.R
12 | import com.seewo.brick.app.widget.Markdown
13 | import com.seewo.brick.ktx.MATCH_PARENT
14 | import com.seewo.brick.ktx.column
15 | import com.seewo.brick.ktx.dp
16 | import com.seewo.brick.ktx.drawable
17 | import com.seewo.brick.ktx.expand
18 | import com.seewo.brick.ktx.frameLayout
19 | import com.seewo.brick.ktx.imageView
20 | import com.seewo.brick.ktx.indicator
21 | import com.seewo.brick.ktx.layoutParams
22 | import com.seewo.brick.ktx.loopPager
23 | import com.seewo.brick.ktx.view
24 | import kotlin.time.Duration.Companion.seconds
25 |
26 | private class LoopViewPagerPage(context: Context, attrs: AttributeSet? = null) :
27 | BrickPreview(context, attrs) {
28 |
29 | override fun preview(context: Context) {
30 | view {
31 | context.LoopViewPagerPage()
32 | }
33 | }
34 | }
35 |
36 | fun Context.LoopViewPagerPage() = column(
37 | MATCH_PARENT, MATCH_PARENT,
38 | ) {
39 | LoopViewPager()
40 | ShowMarkDown()
41 | }
42 |
43 | private fun LinearLayout.LoopViewPager() {
44 | frameLayout(
45 | MATCH_PARENT, 200.dp,
46 | ) {
47 | val viewPager = loopPager(
48 | MATCH_PARENT, MATCH_PARENT,
49 | data = listOf(
50 | R.drawable.page1,
51 | R.drawable.page2,
52 | R.drawable.page3,
53 | ),
54 | duration = 1.seconds,
55 | scrollDuration = 300,
56 | onPageSelected = {
57 | Log.i("BrickUI", "onPageSelected: $it")
58 | }
59 | ) { data, position ->
60 | imageView(
61 | MATCH_PARENT, MATCH_PARENT,
62 | scaleType = ImageView.ScaleType.CENTER_CROP,
63 | drawable = data[position].drawable,
64 | )
65 | }
66 | layoutParams(gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM) {
67 | indicator(
68 | MATCH_PARENT, 48.dp,
69 | viewPager,
70 | )
71 | }
72 | }
73 | }
74 |
75 | private fun LinearLayout.ShowMarkDown() {
76 | expand {
77 | Markdown(
78 | """
79 | ## 代码展示
80 |
81 | 轮播图以1秒间隔翻页
82 |
83 | ```kotlin
84 | private fun LinearLayout.LoopViewPager() {
85 | frameLayout(
86 | MATCH_PARENT, 200.dp,
87 | ) {
88 | val viewPager = loopPager(
89 | MATCH_PARENT, MATCH_PARENT,
90 | data = listOf(
91 | R.drawable.page1,
92 | R.drawable.page2,
93 | R.drawable.page3,
94 | ),
95 | duration = 1.seconds,
96 | onPageSelected = {
97 | Log.i("BrickUI", "onPageSelected: ${'$'}it")
98 | }
99 | ) { data, position ->
100 | imageView(
101 | MATCH_PARENT, MATCH_PARENT,
102 | scaleType = ImageView.ScaleType.CENTER_CROP,
103 | drawable = data[position].drawable,
104 | )
105 | }
106 | layoutParams(gravity = Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM) {
107 | indicator(
108 | MATCH_PARENT, 48.dp,
109 | viewPager,
110 | )
111 | }
112 | }
113 | }
114 | ```
115 | """.trimIndent()
116 | )
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/ExtraFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.hjq.toast.ToastUtils
6 | import com.seewo.brick.BrickPreview
7 | import com.seewo.brick.app.R
8 | import com.seewo.brick.app.extra.about.AboutActivity
9 | import com.seewo.brick.app.extra.counter.CounterActivity
10 | import com.seewo.brick.app.extra.list.LongListActivity
11 | import com.seewo.brick.app.main.MainItemBean
12 | import com.seewo.brick.app.main.mainFragmentList
13 | import com.seewo.brick.ktx.*
14 |
15 | class PreviewExtraFragment(context: Context, attrs: AttributeSet? = null) :
16 | BrickPreview(context, attrs) {
17 |
18 | override fun preview(context: Context) {
19 | view {
20 | context.ExtraPage()
21 | }
22 | }
23 | }
24 |
25 | fun Context.ExtraPage() = mainFragmentList(
26 | listOf(
27 | MainItemBean("计数器", R.drawable.btn_add_food.drawable) {
28 | startActivity()
29 | },
30 | MainItemBean("长列表体验", R.drawable.ic_widget_picker_view.drawable) {
31 | startActivity()
32 | },
33 | MainItemBean("To-Do", R.drawable.ic_checked_right.drawable) {
34 | ToastUtils.show("有空再搞")
35 | },
36 | MainItemBean("关于", R.mipmap.ic_launcher.drawable?.clipRect(8.dp)) {
37 | startActivity()
38 | },
39 | )
40 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/about/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.about
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.ktx.setStatusBarTransparent
6 |
7 | class AboutActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | setStatusBarTransparent(true)
12 | setContentView(AboutPage())
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/about/AboutPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.about
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.graphics.Color
6 | import android.graphics.Typeface
7 | import android.net.Uri
8 | import android.text.method.LinkMovementMethod
9 | import android.util.AttributeSet
10 | import android.view.Gravity
11 | import android.view.ViewGroup
12 | import android.widget.LinearLayout
13 | import androidx.core.text.buildSpannedString
14 | import com.seewo.brick.BrickPreview
15 | import com.seewo.brick.app.R
16 | import com.seewo.brick.app.widget.TopBar
17 | import com.seewo.brick.ktx.*
18 | import com.seewo.brick.params.EdgeInsets
19 |
20 | class AboutPage(context: Context, attrs: AttributeSet): BrickPreview(context, attrs) {
21 | override fun preview(context: Context) {
22 | view {
23 | context.AboutPage()
24 | }
25 | }
26 | }
27 |
28 | fun Context.AboutPage() = column(
29 | MATCH_PARENT, MATCH_PARENT,
30 | gravity = Gravity.CENTER_HORIZONTAL,
31 | fitsSystemWindows = true,
32 | ) {
33 | TopBar()
34 | LOGO()
35 | Title()
36 | TextBody()
37 | Links()
38 | }
39 |
40 | private fun ViewGroup.Links() {
41 | row(
42 | padding = EdgeInsets.only(bottom = 32.dp)
43 | ) {
44 | textView(
45 | text = buildSpannedString {
46 | appendClickable(
47 | "BrickUI@github",
48 | isUnderlineText = false,
49 | ) {
50 | context.startActivity(Intent(Intent.ACTION_VIEW).apply {
51 | data = Uri.parse("https://github.com/robin8yeung/BrickUI")
52 | })
53 | }
54 | },
55 | textSize = 14.dp,
56 | padding = EdgeInsets.only(end = 8.dp),
57 | movementMethod = LinkMovementMethod(),
58 | highLightColor = Color.TRANSPARENT,
59 | )
60 | divider(
61 | 1.dp, 16.dp,
62 | background = R.color.grey_e4.colorDrawable,
63 | )
64 | textView(
65 | text = buildSpannedString {
66 | appendClickable(
67 | "BrickUI@gitlab(内部)",
68 | isUnderlineText = false,
69 | ) {
70 | context.startActivity(Intent(Intent.ACTION_VIEW).apply {
71 | data = Uri.parse("https://gitlab.gz.cvte.cn/seewocbb/BrickUI")
72 | })
73 | }
74 | },
75 | textSize = 14.dp,
76 | padding = EdgeInsets.only(start = 8.dp),
77 | movementMethod = LinkMovementMethod(),
78 | highLightColor = Color.TRANSPARENT,
79 | )
80 | }
81 | }
82 |
83 | private fun LinearLayout.Title() {
84 | textView(
85 | text = "BrickUI",
86 | textSize = 24.dp,
87 | textColor = R.color.primary.color,
88 | padding = EdgeInsets.only(bottom = 48.dp),
89 | textStyle = Typeface.BOLD,
90 | )
91 | }
92 |
93 | private fun LinearLayout.TextBody() {
94 | expand {
95 | textView(
96 | MATCH_PARENT, MATCH_PARENT,
97 | text = """
98 | 受Jetpack Compose启发,通过组合和声明的方式去搭建UI,就像用砖头垒出来的一样自然。
99 |
100 | BrickUI是一套Kotlin实现的,基于原生View体系的声明式UI框架。
101 | 与原生View体系无缝对接,从此代码徒手撸layout,忘记你的xml吧~
102 | """.trimIndent(),
103 | textSize = 16.dp,
104 | padding = EdgeInsets.only(bottom = 16.dp, start = 32.dp, end = 32.dp),
105 | textColor = Color.GRAY,
106 | )
107 | }
108 | }
109 |
110 | private fun LinearLayout.LOGO() {
111 | layoutParams(margins = EdgeInsets.only(top = 32.dp, bottom = 16.dp)) {
112 | roundRectClip(
113 | radius = 8.dp
114 | ) {
115 | imageView(
116 | 64.dp, 64.dp,
117 | drawable = R.mipmap.ic_launcher.drawable,
118 | )
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/counter/CounterActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.counter
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.ktx.setStatusBarTransparent
6 |
7 | class CounterActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | setStatusBarTransparent(true)
12 | setContentView(CounterPage())
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/counter/CounterPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.counter
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.graphics.Typeface
6 | import android.graphics.drawable.ColorDrawable
7 | import android.util.AttributeSet
8 | import android.view.Gravity
9 | import android.view.View
10 | import android.view.ViewGroup
11 | import android.widget.LinearLayout
12 | import com.seewo.brick.BrickPreview
13 | import com.seewo.brick.app.R
14 | import com.seewo.brick.app.widget.Markdown
15 | import com.seewo.brick.app.widget.TopBar
16 | import com.seewo.brick.ktx.*
17 | import com.seewo.brick.params.EdgeInsets
18 | import com.seewo.brick.params.Shadow
19 |
20 |
21 | class CounterPage(context: Context, attrs: AttributeSet?) : BrickPreview(context, attrs) {
22 | override fun preview(context: Context) {
23 | view {
24 | context.CounterPage()
25 | }
26 | }
27 | }
28 |
29 | fun Context.CounterPage() = column(
30 | MATCH_PARENT, MATCH_PARENT,
31 | fitsSystemWindows = true,
32 | ) {
33 | // 通过上下文获取ViewModel,这样可以保证在任何嵌套下均能获取到Activity的ViewModel
34 | val viewModel: CounterPageViewModel? = context.activityViewModelOrNull()
35 |
36 | TopBar()
37 | divider(background = ColorDrawable(Color.GRAY))
38 | row(
39 | MATCH_PARENT, 160.dp,
40 | gravity = Gravity.CENTER,
41 | fitsSystemWindows = true,
42 | ) {
43 | button("-") {
44 | viewModel?.minus()
45 | }
46 | liveText(
47 | 84.dp,
48 | style = R.style.BigNumber,
49 | text = viewModel?.count?.map { it.toString() } ?: "0".static, // 为了在预览模式能看到0的效果
50 | textColor = viewModel?.count?.map { if (it % 2 == 0) Color.RED else Color.BLACK },
51 | padding = EdgeInsets.all(12.dp),
52 | )
53 | button("+") {
54 | viewModel?.plus()
55 | }
56 | }
57 | ShowMarkDown()
58 | }
59 |
60 | private fun ViewGroup.button(
61 | text: String,
62 | onClick: View.OnClickListener
63 | ) = shadowBox(
64 | radius = 14.dp, shadow = Shadow(blur = 8.dp),
65 | onClick = onClick
66 | ) {
67 | textView(
68 | width = 100.dp, height = 100.dp,
69 | text = text,
70 | textSize = 28.dp,
71 | textStyle = Typeface.BOLD,
72 | gravity = Gravity.CENTER
73 | )
74 | }
75 |
76 |
77 | private fun LinearLayout.ShowMarkDown() {
78 | expand {
79 | Markdown(
80 | """
81 | ## 最佳实践
82 |
83 | ### 架构
84 |
85 | 与Flutter的默认demo类似,这里给到一个简单的计数器demo,用于阐释一个带有具体业务的例子。
86 | BrickUI作为基于View体系的一套框架,对标的实际更多是DataBinding,所以最佳实践仍然是采用MVVM架构。
87 |
88 | ### 数据绑定
89 |
90 | 相比DataBind,我们不需要再在xml里面写逻辑,而且brick-ui-live提供了比DataBinding更纯粹而有效的双向绑定,可以参考其中liveEdit、liveCheckBox、liveSeekBar等的实现
91 |
92 | ### 代码展示
93 | 篇幅有限,这里就不展示代码了,请到demo源码去看吧
94 | """.trimIndent()
95 | )
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/counter/CounterPageViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.counter
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.AndroidViewModel
5 | import androidx.lifecycle.LiveData
6 | import com.seewo.brick.ktx.data
7 | import com.seewo.brick.ktx.live
8 |
9 | class CounterPageViewModel(application: Application): AndroidViewModel(application) {
10 | val count: LiveData = 0.live
11 |
12 | fun plus() {
13 | count.data = count.data + 1
14 | }
15 |
16 | fun minus() {
17 | count.data = count.data - 1
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/extra/list/LongListActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.extra.list
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.ktx.setStatusBarTransparent
6 |
7 | class LongListActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | setStatusBarTransparent(true)
12 | setContentView(LongListPage())
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/helper/HelperFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.helper
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import com.seewo.brick.BrickPreview
6 | import com.seewo.brick.app.R
7 | import com.seewo.brick.app.helper.animator.AnimatorHelperActivity
8 | import com.seewo.brick.app.helper.clip.ClipAndShadowHelperActivity
9 | import com.seewo.brick.app.helper.color.ColorAndDrawableHelperActivity
10 | import com.seewo.brick.app.helper.spannable.SpannableHelperActivity
11 | import com.seewo.brick.app.main.MainItemBean
12 | import com.seewo.brick.app.main.mainFragmentList
13 | import com.seewo.brick.ktx.drawable
14 | import com.seewo.brick.ktx.startActivity
15 | import com.seewo.brick.ktx.view
16 |
17 | class PreviewHelperFragment(context: Context, attrs: AttributeSet? = null) :
18 | BrickPreview(context, attrs) {
19 |
20 | override fun preview(context: Context) {
21 | view {
22 | context.HelperPage()
23 | }
24 | }
25 | }
26 |
27 | fun Context.HelperPage() = mainFragmentList(
28 | listOf(
29 | MainItemBean("裁剪与阴影", R.drawable.ic_util_drawable.drawable) {
30 | startActivity()
31 | },
32 | MainItemBean("颜色与Drawable", R.drawable.ic_util_color.drawable) {
33 | startActivity()
34 | },
35 | MainItemBean("富文本", R.drawable.ic_widget_dialog.drawable) {
36 | startActivity()
37 | },
38 | MainItemBean("动画", R.drawable.ic_widget_loading.drawable) {
39 | startActivity()
40 | },
41 | )
42 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/helper/animator/AnimatorHelperActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.helper.animator
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.helper.animator.page.AnimatorPage
6 | import com.seewo.brick.app.widget.multiTabViewPager
7 | import com.seewo.brick.ktx.MATCH_PARENT
8 | import com.seewo.brick.ktx.frameLayout
9 | import com.seewo.brick.ktx.setStatusBarTransparent
10 |
11 | class AnimatorHelperActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setStatusBarTransparent(true)
16 | setContentView(multiTabViewPager(
17 | data = listOf(
18 | "动画",
19 | ),
20 | viewPagerBuilder = { _, index ->
21 | when (index) {
22 | 0 -> AnimatorPage()
23 |
24 | else -> frameLayout(
25 | MATCH_PARENT, MATCH_PARENT,
26 | )
27 | }
28 | }
29 | ))
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/helper/clip/ClipAndShadowHelperActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.helper.clip
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.helper.clip.page.ClipPage
6 | import com.seewo.brick.app.helper.clip.page.ShadowPage
7 | import com.seewo.brick.app.widget.multiTabViewPager
8 | import com.seewo.brick.ktx.MATCH_PARENT
9 | import com.seewo.brick.ktx.frameLayout
10 | import com.seewo.brick.ktx.setStatusBarTransparent
11 |
12 | class ClipAndShadowHelperActivity : AppCompatActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setStatusBarTransparent(true)
17 | setContentView(multiTabViewPager(
18 | data = listOf(
19 | "阴影",
20 | "裁剪",
21 | ),
22 | viewPagerBuilder = { _, index ->
23 | when (index) {
24 | 0 -> ShadowPage()
25 | 1 -> ClipPage()
26 |
27 | else -> frameLayout(
28 | MATCH_PARENT, MATCH_PARENT,
29 | )
30 | }
31 | }
32 | ))
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/helper/color/ColorAndDrawableHelperActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.helper.color
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.helper.color.page.ColorPage
6 | import com.seewo.brick.app.helper.color.page.DrawablePage
7 | import com.seewo.brick.app.widget.multiTabViewPager
8 | import com.seewo.brick.ktx.MATCH_PARENT
9 | import com.seewo.brick.ktx.frameLayout
10 | import com.seewo.brick.ktx.setStatusBarTransparent
11 |
12 | class ColorAndDrawableHelperActivity : AppCompatActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setStatusBarTransparent(true)
17 | setContentView(multiTabViewPager(
18 | data = listOf(
19 | "颜色",
20 | "Drawable",
21 | ),
22 | viewPagerBuilder = { _, index ->
23 | when (index) {
24 | 0 -> ColorPage()
25 | 1 -> DrawablePage()
26 |
27 | else -> frameLayout(
28 | MATCH_PARENT, MATCH_PARENT,
29 | )
30 | }
31 | }
32 | ))
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/helper/spannable/SpannableHelperActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.helper.spannable
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.app.helper.spannable.page.SpannablePage
6 | import com.seewo.brick.app.widget.multiTabViewPager
7 | import com.seewo.brick.ktx.MATCH_PARENT
8 | import com.seewo.brick.ktx.frameLayout
9 | import com.seewo.brick.ktx.setStatusBarTransparent
10 |
11 | class SpannableHelperActivity : AppCompatActivity() {
12 |
13 | override fun onCreate(savedInstanceState: Bundle?) {
14 | super.onCreate(savedInstanceState)
15 | setStatusBarTransparent(true)
16 | setContentView(multiTabViewPager(
17 | data = listOf(
18 | "富文本",
19 | ),
20 | viewPagerBuilder = { _, index ->
21 | when (index) {
22 | 0 -> SpannablePage()
23 |
24 | else -> frameLayout(
25 | MATCH_PARENT, MATCH_PARENT,
26 | )
27 | }
28 | }
29 | ))
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.main
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.seewo.brick.ktx.setStatusBarTransparent
6 |
7 | class MainActivity : AppCompatActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setStatusBarTransparent(true)
11 | setContentView(mainPage())
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/main/MainFragmentList.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.main
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.ViewGroup
6 | import androidx.recyclerview.widget.GridLayoutManager
7 | import androidx.recyclerview.widget.RecyclerView
8 | import com.seewo.brick.BrickPreview
9 | import com.seewo.brick.app.R
10 | import com.seewo.brick.ktx.MATCH_PARENT
11 | import com.seewo.brick.ktx.drawable
12 | import com.seewo.brick.ktx.simpleStatelessRecyclerView
13 |
14 | class MainFragmentList(context: Context, attrs: AttributeSet): BrickPreview(context, attrs) {
15 | override fun preview(context: Context) {
16 | mainFragmentList(listOf(
17 | MainItemBean("计数器", R.drawable.btn_add_food.drawable),
18 | MainItemBean("To-Do", R.drawable.ic_checked_right.drawable),
19 | MainItemBean("关于", R.mipmap.ic_launcher.drawable),
20 | ))
21 | }
22 | }
23 |
24 | fun Context.mainFragmentList(
25 | items: List
26 | ) = simpleStatelessRecyclerView(
27 | MATCH_PARENT, MATCH_PARENT,
28 | data = items,
29 | layoutManager = GridLayoutManager(this, 3),
30 | overScrollMode = RecyclerView.OVER_SCROLL_NEVER,
31 | ) { data, i ->
32 | MainItemWidget(
33 | text = data[i].text,
34 | drawable = data[i].drawable,
35 | onClick = data[i].onClick,
36 | )
37 | }
38 |
39 | fun ViewGroup.mainFragmentList(
40 | items: List
41 | ) = context.mainFragmentList(items).also { addView(it) }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/main/MainItemBean.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.main
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.graphics.drawable.Drawable
6 | import android.text.TextUtils
7 | import android.util.AttributeSet
8 | import android.view.Gravity
9 | import android.view.View.OnClickListener
10 | import android.view.ViewGroup
11 | import com.seewo.brick.BrickPreview
12 | import com.seewo.brick.app.R
13 | import com.seewo.brick.ktx.MATCH_PARENT
14 | import com.seewo.brick.ktx.column
15 | import com.seewo.brick.ktx.dp
16 | import com.seewo.brick.ktx.drawable
17 | import com.seewo.brick.ktx.imageView
18 | import com.seewo.brick.ktx.rectDrawable
19 | import com.seewo.brick.ktx.stateListDrawable
20 | import com.seewo.brick.ktx.textView
21 | import com.seewo.brick.params.EdgeInsets
22 |
23 | class PreviewMainItem(context: Context, attrs: AttributeSet? = null): BrickPreview(context, attrs) {
24 |
25 | override fun preview(context: Context) {
26 | MainItemWidget(
27 | "Hello Brick",
28 | R.mipmap.ic_launcher.drawable,
29 | )
30 | }
31 | }
32 |
33 | class MainItemBean(
34 | val text: String,
35 | val drawable: Drawable? = null,
36 | val onClick: OnClickListener? = null,
37 | )
38 |
39 | fun ViewGroup.MainItemWidget(
40 | text: String,
41 | drawable: Drawable? = null,
42 | onClick: OnClickListener? = null,
43 | ) = column(
44 | MATCH_PARENT, 120.dp,
45 | padding = EdgeInsets.symmetric(horizontal = 8.dp, vertical = 10.dp),
46 | gravity = Gravity.CENTER,
47 | background = stateListDrawable(
48 | mapOf(
49 | intArrayOf(-android.R.attr.state_pressed) to rectDrawable(fillColor = Color.WHITE),
50 | intArrayOf(android.R.attr.state_pressed) to rectDrawable(fillColor = Color.parseColor("#E4E4E4")),
51 | )
52 | ),
53 | onClick = onClick,
54 | ) {
55 | imageView(
56 | 48.dp, 48.dp,
57 | drawable = drawable,
58 | )
59 | textView(
60 | text = text,
61 | maxLines = 1,
62 | ellipsize = TextUtils.TruncateAt.END,
63 | margin = EdgeInsets.all(8.dp),
64 | )
65 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/main/MainPage.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.main
2 |
3 | import android.content.Context
4 | import android.graphics.Typeface
5 | import android.util.AttributeSet
6 | import android.view.Gravity
7 | import com.seewo.brick.BrickPreview
8 | import com.seewo.brick.app.R
9 | import com.seewo.brick.app.component.ComponentPage
10 | import com.seewo.brick.app.extra.ExtraPage
11 | import com.seewo.brick.app.helper.HelperPage
12 | import com.seewo.brick.ktx.MATCH_PARENT
13 | import com.seewo.brick.ktx.colorDrawable
14 | import com.seewo.brick.ktx.column
15 | import com.seewo.brick.ktx.divider
16 | import com.seewo.brick.ktx.dp
17 | import com.seewo.brick.ktx.drawable
18 | import com.seewo.brick.ktx.expand
19 | import com.seewo.brick.ktx.live
20 | import com.seewo.brick.ktx.liveTabLayout
21 | import com.seewo.brick.ktx.liveViewPager
22 | import com.seewo.brick.ktx.static
23 | import com.seewo.brick.ktx.textView
24 | import com.seewo.brick.ktx.view
25 | import com.seewo.brick.params.CompoundDrawables
26 | import com.seewo.brick.params.EdgeInsets
27 |
28 | class MainPage(context: Context, attributeSet: AttributeSet?) :
29 | BrickPreview(context, attributeSet) {
30 | override fun preview(context: Context) {
31 | view {
32 | context.mainPage()
33 | }
34 | }
35 | }
36 |
37 | fun Context.mainPage() = column(
38 | MATCH_PARENT, MATCH_PARENT,
39 | fitsSystemWindows = true
40 | ) {
41 | val currentIndex = 0.live
42 | val tabs = listOf(
43 | Pair(R.drawable.selector_icon_tabbar_component, "控件"),
44 | Pair(R.drawable.selector_icon_tabbar_util, "工具"),
45 | Pair(R.drawable.selector_icon_tabbar_expand, "扩展"),
46 | ).static
47 | expand {
48 | liveViewPager(
49 | MATCH_PARENT, MATCH_PARENT,
50 | data = tabs,
51 | currentIndex = currentIndex,
52 | smoothScroll = false,
53 | isUserInputEnable = false,
54 | ) { _, index ->
55 | when (index) {
56 | 0 -> ComponentPage()
57 | 1 -> HelperPage()
58 | else -> ExtraPage()
59 | }
60 | }
61 | }
62 | divider(height = 1.dp, background = R.color.grey_e4.colorDrawable)
63 | liveTabLayout(
64 | MATCH_PARENT, 64.dp,
65 | data = tabs,
66 | margin = EdgeInsets.symmetric(horizontal = 44.dp),
67 | currentIndex = currentIndex,
68 | ) { _, item ->
69 | textView(
70 | text = item.second,
71 | style = R.style.TabStyle,
72 | compoundDrawables = CompoundDrawables(
73 | top = item.first.drawable
74 | ),
75 | textStyle = Typeface.BOLD,
76 | gravity = Gravity.CENTER,
77 | )
78 | }
79 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/widget/CommonKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.widget
2 |
3 | import android.graphics.drawable.Drawable
4 | import com.seewo.brick.app.R
5 | import com.seewo.brick.ktx.*
6 | import com.seewo.brick.params.CornerRadius
7 |
8 | val buttonBackGround: Drawable
9 | get() = stateListDrawable(
10 | mapOf(
11 | intArrayOf(-android.R.attr.state_enabled) to rectDrawable(
12 | fillColor = R.color.primary.color.withAlpha(0.4f),
13 | corners = CornerRadius.all(4.dp),
14 | ),
15 | intArrayOf(android.R.attr.state_pressed) to rectDrawable(
16 | fillColor = R.color.primary.color.withAlpha(0.6f),
17 | corners = CornerRadius.all(4.dp),
18 | ),
19 | intArrayOf(
20 | -android.R.attr.state_pressed,
21 | android.R.attr.state_enabled
22 | ) to rectDrawable(
23 | fillColor = R.color.primary.color,
24 | corners = CornerRadius.all(4.dp),
25 | ),
26 | )
27 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/widget/Markdown.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.widget
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import club.andnext.markdown.MarkdownWebView
7 | import com.seewo.brick.ktx.MATCH_PARENT
8 | import com.seewo.brick.ktx.init
9 | import com.seewo.brick.ktx.placeholder
10 | import com.seewo.brick.ktx.view
11 |
12 | fun ViewGroup.Markdown(
13 | text: String
14 | ): View {
15 | if (isInEditMode) return placeholder() // 避免预览模式报错
16 | return view {
17 | // 第三方控件:MarkdownWebView
18 | MarkdownWebView(context).apply {
19 | // 初始化宽高
20 | init(MATCH_PARENT, MATCH_PARENT)
21 | setText(text)
22 | }
23 | }
24 | }
25 |
26 | fun Context.Markdown(
27 | text: String
28 | ): View {
29 | return MarkdownWebView(this).apply {
30 | // 初始化宽高
31 | init(MATCH_PARENT, MATCH_PARENT)
32 | setText(text)
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/widget/SeekValue.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.widget
2 |
3 | import android.graphics.Color
4 | import android.view.Gravity
5 | import android.widget.LinearLayout
6 | import androidx.lifecycle.MutableLiveData
7 | import com.seewo.brick.app.R
8 | import com.seewo.brick.ktx.*
9 | import com.seewo.brick.params.CornerRadius
10 | import com.seewo.brick.params.EdgeInsets
11 |
12 | fun LinearLayout.SeekValue(
13 | name: String,
14 | max: Int,
15 | value: MutableLiveData,
16 | valueMapper: (Int) -> String
17 | ) {
18 | row(MATCH_PARENT, 24.dp) {
19 | textView(
20 | 60.dp,
21 | text = name
22 | )
23 | expand {
24 | liveSeekBar(
25 | MATCH_PARENT, 12.dp,
26 | thumb = ovalDrawable(
27 | width = 12.dp,
28 | height = 12.dp,
29 | strokeWidth = 1.dp,
30 | strokeColor = R.color.primary.color,
31 | fillColor = Color.WHITE,
32 | ),
33 | thumbOffset = 2.dp,
34 | progressBackground = rectDrawable(
35 | fillColor = R.color.grey_e4.color,
36 | corners = CornerRadius.all(60.dp),
37 | ),
38 | progressDrawable = rectDrawable(
39 | fillColor = R.color.primary.color,
40 | corners = CornerRadius.all(60.dp),
41 | ),
42 | progress = value,
43 | max = max,
44 | padding = EdgeInsets.symmetric(vertical = 4.dp, horizontal = 2.dp)
45 | )
46 | }
47 | liveText(
48 | 40.dp,
49 | text = value.map(valueMapper),
50 | gravity = Gravity.END,
51 | )
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/seewo/brick/app/widget/TopBar.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.app.widget
2 |
3 | import android.app.Activity
4 | import android.view.ViewGroup
5 | import android.widget.ImageView
6 | import com.seewo.brick.app.R
7 | import com.seewo.brick.ktx.*
8 |
9 | fun ViewGroup.TopBar() {
10 | row(
11 | MATCH_PARENT, 44.dp,
12 | ) {
13 | imageView(
14 | 44.dp, 44.dp,
15 | drawable = R.drawable.ic_back_dark.drawable,
16 | scaleType = ImageView.ScaleType.CENTER_INSIDE,
17 | ) {
18 | (context as? Activity)?.onBackPressed()
19 | }
20 | expand()
21 | }
22 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_expand_web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_expand_web.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_util_color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_util_color.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_util_drawable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_util_drawable.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_button.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_dialog.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_flowlayout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_flowlayout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_layout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_layout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_loading.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_picker_view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_picker_view.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_spinner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_spinner.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_statelayout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_statelayout.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_widget_titlebar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/ic_widget_titlebar.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_component.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_component.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_component_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_component_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_expand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_expand.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_expand_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_expand_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_util.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_util.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/icon_tabbar_util_selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-hdpi/icon_tabbar_util_selected.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/btn_add_food.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/btn_add_food.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_back_white.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/ic_back_white.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/page1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/page1.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/page2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/page2.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/page3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/page3.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/tab_courseware_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/tab_courseware_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/tab_courseware_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/tab_courseware_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/tab_me_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/tab_me_normal.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/tab_me_press.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/drawable-xhdpi/tab_me_press.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_back_dark.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_checked_right.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_well_chosen.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selector_icon_tabbar_component.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selector_icon_tabbar_expand.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/selector_icon_tabbar_util.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_me.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_permission.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/white_radius.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/app/src/main/res/mipmap/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #E4E4E4
11 | #399EE3
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 4dp
5 | 5dp
6 | 6dp
7 | 2dp
8 | 180dp
9 | 16dp
10 | 16dp
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
13 |
18 |
19 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
24 |
25 |
26 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | apply from: "${project.rootDir}/dependencies.gradle"
4 |
5 | dependencies {
6 | classpath "com.android.tools:r8:3.3.28"
7 | }
8 | }
9 |
10 | plugins {
11 | id 'com.android.application' version '7.2.1' apply false
12 | id 'com.android.library' version '7.2.1' apply false
13 | id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
14 | }
15 |
16 | task clean(type: Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
20 | try {
21 | // Jenkins 打包时会调用这里
22 | apply from: "${project.rootDir}/gradles/utils.gradle"
23 | } catch(Exception ignored) {
24 | }
--------------------------------------------------------------------------------
/core/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/core/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | kotlinOptions {
27 | jvmTarget = '1.8'
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation rootProject.ext.deps.kotlin.coroutines.core
33 | implementation rootProject.ext.deps.kotlin.coroutines.android
34 |
35 | implementation rootProject.ext.deps.android.appcompat
36 | implementation rootProject.ext.deps.android.material
37 |
38 | implementation rootProject.ext.deps.jetpack.startup
39 | implementation rootProject.ext.deps.ktx.core
40 | implementation rootProject.ext.deps.ktx.activity
41 |
42 | implementation rootProject.ext.deps.android.flexbox
43 | }
44 |
45 | try {
46 | // Jenkins 打包时会调用这里
47 | apply from: "${project.rootDir}/gradles/jitpack-push.gradle"
48 | apply from: "${project.rootDir}/gradles/jfrog-push.gradle"
49 | } catch(Exception ignored) {
50 | }
--------------------------------------------------------------------------------
/core/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/core/consumer-rules.pro
--------------------------------------------------------------------------------
/core/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=brick-ui
2 | POM_NAME=brick-ui
3 | POM_DESCRIPTION=BrickUI
--------------------------------------------------------------------------------
/core/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/core/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/BrickPreview.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.widget.FrameLayout
6 | import com.seewo.brick.ktx.MATCH_PARENT
7 | import com.seewo.brick.ktx.init
8 |
9 | abstract class BrickPreview(context: Context, attributeSet: AttributeSet? = null): FrameLayout(context, attributeSet) {
10 | init {
11 | BrickUI.init(context)
12 | init(MATCH_PARENT, MATCH_PARENT)
13 | preview(context)
14 | }
15 |
16 | abstract fun preview(context: Context)
17 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/BrickUI.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.res.Resources
6 | import android.graphics.drawable.Drawable
7 | import android.util.Log
8 | import android.util.TypedValue
9 | import androidx.annotation.ColorInt
10 | import androidx.annotation.ColorRes
11 | import androidx.annotation.DimenRes
12 | import androidx.annotation.DrawableRes
13 | import androidx.annotation.StringRes
14 | import androidx.core.content.res.ResourcesCompat
15 |
16 | @SuppressLint("StaticFieldLeak")
17 | object BrickUI {
18 | private lateinit var context: Context
19 |
20 | /**
21 | * 通过StartUp调用,不需要自行调用
22 | * @see com.seewo.brick.init.BrickUIInitializer
23 | */
24 | fun init(context: Context) {
25 | Log.d("BrickUI", "[ Hello world ]")
26 | this.context = context.applicationContext
27 | }
28 |
29 | //把px转换成dp
30 | fun dipToPixel(dip: Float): Int {
31 | return TypedValue.applyDimension(
32 | TypedValue.COMPLEX_UNIT_DIP, dip,
33 | context.resources.displayMetrics
34 | ).toInt()
35 | }
36 |
37 | fun spToPixel(sp: Float): Int = TypedValue.applyDimension(
38 | TypedValue.COMPLEX_UNIT_SP, sp,
39 | context.resources.displayMetrics
40 | ).toInt()
41 |
42 | fun pxToDp(px: Int): Int {
43 | return pxToDp(context, px)
44 | }
45 |
46 | private fun pxToDp(context: Context, px: Int): Int {
47 | val scale = context.resources.displayMetrics.density
48 | return (px / scale + 0.5f).toInt()
49 | }
50 |
51 | fun string(@StringRes id: Int) = context.getString(id)
52 |
53 | fun string(@StringRes id: Int, vararg params: Any) = context.getString(id, *params)
54 |
55 | @ColorInt
56 | fun color(@ColorRes color: Int, theme: Resources.Theme? = null) =
57 | ResourcesCompat.getColor(context.resources, color, theme)
58 |
59 | fun drawable(@DrawableRes drawable: Int, theme: Resources.Theme? = null): Drawable? =
60 | ResourcesCompat.getDrawable(context.resources, drawable, theme)
61 |
62 | fun dimension(@DimenRes id: Int) =
63 | context.resources.getDimension(id).toInt()
64 |
65 | val applicationContext: Context
66 | get() = context
67 | }
68 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/JavaDrawableUtils.java:
--------------------------------------------------------------------------------
1 | package com.seewo.brick;
2 |
3 | import android.graphics.drawable.ClipDrawable;
4 | import android.graphics.drawable.Drawable;
5 | import android.graphics.drawable.ScaleDrawable;
6 | import android.view.Gravity;
7 |
8 | import androidx.annotation.NonNull;
9 |
10 | public class JavaDrawableUtils {
11 | private JavaDrawableUtils() {}
12 |
13 | /**
14 | * 由于Kotlin编译成以下语句,而DrawableWrapper在 sdkVersion 23 才支持,导致低版本设备崩溃
15 | *
16 | * var21[1] = (Drawable)(progressType == 1 ? (DrawableWrapper)(new ClipDrawable(progressDrawable, 8388611, 1)) : (DrawableWrapper)(new ScaleDrawable(progressDrawable, 8388611, 1.0F, -1.0F)));
17 | */
18 | @NonNull
19 | public static Drawable getDrawableWrapper(Drawable innerDrawable, int type) {
20 | if (type == 1) {
21 | return getClipDrawable(innerDrawable);
22 | } else {
23 | return getScaleDrawable(innerDrawable);
24 | }
25 | }
26 |
27 | @NonNull
28 | public static ScaleDrawable getScaleDrawable(Drawable innerDrawable) {
29 | return new ScaleDrawable(innerDrawable, Gravity.START, 1f, -1f);
30 | }
31 |
32 | @NonNull
33 | public static ClipDrawable getClipDrawable(Drawable innerDrawable) {
34 | return new ClipDrawable(innerDrawable, Gravity.START, ClipDrawable.HORIZONTAL);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/cache/DrawableCache.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.cache
2 |
3 | import android.graphics.drawable.Drawable
4 | import java.lang.ref.SoftReference
5 |
6 | internal object DrawableCache {
7 | private val cacheMap: MutableMap> = mutableMapOf()
8 |
9 | fun put(key: String, value: Drawable) {
10 | cacheMap[key] = SoftReference(value)
11 | }
12 |
13 | inline fun get(key: String): T? {
14 | val reference = cacheMap[key]
15 | val drawable = reference?.get()
16 | if (reference != null && drawable == null) {
17 | cacheMap.remove(key)
18 | }
19 | return drawable as? T
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/drawable/OvalClipDrawable.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.drawable
2 |
3 | import android.graphics.*
4 | import android.graphics.Shader.TileMode
5 | import android.graphics.drawable.Drawable
6 | import androidx.core.graphics.drawable.toBitmap
7 | import kotlin.math.min
8 |
9 |
10 | class OvalClipDrawable : Drawable {
11 | private val mBitmap: Bitmap
12 | private val mPaint : Paint = Paint()
13 | private val mRadius : Float
14 | private var mRectF : RectF
15 |
16 | constructor(bitmap: Bitmap) {
17 | mBitmap = bitmap
18 | init()
19 | mRadius = min(mBitmap.width, mBitmap.height) / 2f
20 | mRectF = RectF(0f, 0f, mBitmap.width.toFloat(), mBitmap.height.toFloat())
21 | }
22 |
23 | constructor(drawable: Drawable) {
24 | mBitmap = drawable.toBitmap()
25 | init()
26 | mRadius = min(mBitmap.width, mBitmap.height) / 2f
27 | mRectF = RectF(0f, 0f, mBitmap.width.toFloat(), mBitmap.height.toFloat())
28 | }
29 |
30 | private fun init() {
31 | //初始化画笔
32 | mPaint.apply {
33 | isAntiAlias = true
34 | isDither = true
35 | shader = BitmapShader(mBitmap, TileMode.CLAMP, TileMode.CLAMP)
36 | }
37 | }
38 |
39 | override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
40 | super.setBounds(left, top, right, bottom)
41 | mRectF = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
42 | }
43 |
44 | override fun draw(canvas: Canvas) {
45 | canvas.drawCircle(mBitmap.width / 2f, mBitmap.height / 2f, mRadius, mPaint)
46 | }
47 |
48 | override fun getIntrinsicWidth(): Int {
49 | return (mRadius * 2).toInt()
50 | }
51 |
52 | override fun getIntrinsicHeight(): Int {
53 | return (mRadius * 2).toInt()
54 | }
55 |
56 | override fun setAlpha(alpha: Int) {
57 | mPaint.alpha = alpha
58 | }
59 |
60 | override fun setColorFilter(cf: ColorFilter?) {
61 | mPaint.colorFilter = cf
62 | }
63 |
64 | @Deprecated("Deprecated in Java")
65 | override fun getOpacity(): Int {
66 | return PixelFormat.TRANSLUCENT
67 | }
68 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/drawable/RectClipDrawable.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.drawable
2 |
3 | import android.graphics.*
4 | import android.graphics.drawable.BitmapDrawable
5 | import android.graphics.drawable.Drawable
6 | import androidx.core.graphics.drawable.toBitmap
7 | import androidx.core.graphics.toRectF
8 |
9 |
10 | class RectClipDrawable(private val drawable: Drawable, private val radius: Float) :
11 | Drawable() {
12 | private var mBitmap = if (drawable is BitmapDrawable) drawable.bitmap else drawable.toBitmap()
13 | private var mPaint = Paint().apply {
14 | isAntiAlias = true
15 | isDither = true
16 | shader = BitmapShader(
17 | mBitmap,
18 | Shader.TileMode.CLAMP, Shader.TileMode.CLAMP
19 | )
20 | }
21 | private val mWidth: Int = mBitmap.width
22 | private val mHeight: Int = mBitmap.height
23 | private var mRectF: RectF = RectF(0f, 0f, mWidth.toFloat(), mHeight.toFloat())
24 |
25 | //绘制
26 | override fun draw(canvas: Canvas) {
27 | canvas.drawRoundRect(mRectF, radius, radius, mPaint)
28 | }
29 |
30 | override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
31 | super.setBounds(left, top, right, bottom)
32 | mRectF = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
33 | mPaint.shader = BitmapShader(
34 | drawable.toBitmap(right - left, bottom - top).also {
35 | mBitmap = it
36 | },
37 | Shader.TileMode.CLAMP, Shader.TileMode.CLAMP
38 | )
39 | }
40 |
41 | override fun setBounds(bounds: Rect) {
42 | super.setBounds(bounds)
43 | mRectF = bounds.toRectF()
44 | mPaint.shader = BitmapShader(
45 | drawable.toBitmap(bounds.width(), bounds.height()).also {
46 | mBitmap = it
47 | },
48 | Shader.TileMode.CLAMP, Shader.TileMode.CLAMP
49 | )
50 | }
51 |
52 | //设置透明度值
53 | override fun setAlpha(alpha: Int) {
54 | mPaint.alpha = alpha
55 | }
56 |
57 | //设置颜色过滤器
58 | override fun setColorFilter(colorFilter: ColorFilter?) {
59 | mPaint.colorFilter = colorFilter
60 | }
61 |
62 | //返回不透明度
63 | @Deprecated("Deprecated in Java")
64 | override fun getOpacity(): Int {
65 | return PixelFormat.TRANSLUCENT
66 | }
67 |
68 | //返回图片实际的宽高
69 | override fun getIntrinsicWidth(): Int {
70 | return mBitmap.width
71 | }
72 |
73 | override fun getIntrinsicHeight(): Int {
74 | return mBitmap.height
75 | }
76 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/init/BrickUIInitializer.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.init
2 |
3 | import android.content.Context
4 | import androidx.startup.Initializer
5 | import com.seewo.brick.BrickUI
6 |
7 | class BrickUIInitializer : Initializer{
8 | override fun create(context: Context) {
9 | BrickUI.init(context)
10 | }
11 |
12 | override fun dependencies(): MutableList>> = mutableListOf()
13 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/init/ViewInit.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.init
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.os.Build
5 | import android.view.View
6 | import android.view.ViewGroup.MarginLayoutParams
7 | import androidx.annotation.IdRes
8 | import com.seewo.brick.ktx.WRAP_CONTENT
9 | import com.seewo.brick.ktx.init
10 | import com.seewo.brick.params.EdgeInsets
11 |
12 | internal fun View.setup(
13 | width: Int = WRAP_CONTENT,
14 | height: Int = WRAP_CONTENT,
15 | @IdRes id: Int? = null,
16 | tag: Any? = null,
17 | foreground: Drawable? = null,
18 | background: Drawable? = null,
19 | padding: EdgeInsets? = null,
20 | visibility: Int? = null,
21 | isSelected: Boolean? = null,
22 | isEnabled: Boolean? = null,
23 | onClick: View.OnClickListener? = null,
24 | fitsSystemWindows: Boolean? = null,
25 | ) {
26 | init(width, height)
27 | id?.let { this.id = it }
28 | tag?.let { this.tag = it }
29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
30 | foreground?.let {
31 | this.foreground = it
32 | }
33 | }
34 | background?.let { this.background = it }
35 | padding?.let { setPadding(it.start, it.top, it.end, it.bottom) }
36 | visibility?.let { this.visibility = it }
37 | isSelected?.let { this.isSelected = it }
38 | isEnabled?.let { this.isEnabled = it }
39 | onClick?.let { setOnClickListener(it) }
40 | fitsSystemWindows?.let { this.fitsSystemWindows = fitsSystemWindows }
41 | }
42 |
43 | internal fun T.applyMargin(
44 | margin: EdgeInsets? = null,
45 | ): T = apply {
46 | margin?.let {
47 | (layoutParams as? MarginLayoutParams)?.setMargins(
48 | it.start, it.top, it.end, it.bottom
49 | )
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/layout/ConstraintLayoutKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.IdRes
8 | import androidx.annotation.StyleRes
9 | import androidx.constraintlayout.widget.ConstraintLayout
10 | import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams
11 | import com.seewo.brick.init.applyMargin
12 | import com.seewo.brick.init.setup
13 | import com.seewo.brick.params.EdgeInsets
14 | import com.seewo.brick.view.ConstraintHelper
15 |
16 |
17 | /**
18 | * 构建约束布局
19 | *
20 | * @param id 需要配置id,用于声明与父布局的关系
21 | */
22 | fun ViewGroup.constraintLayout(
23 | width: Int = WRAP_CONTENT,
24 | height: Int = WRAP_CONTENT,
25 | @StyleRes style: Int = 0,
26 | @IdRes id: Int,
27 | tag: Any? = null,
28 | foreground: Drawable? = null,
29 | background: Drawable? = null,
30 | margin: EdgeInsets? = null,
31 | padding: EdgeInsets? = null,
32 | visibility: Int? = null,
33 | isSelected: Boolean? = null,
34 | onClick: View.OnClickListener? = null,
35 | fitsSystemWindows: Boolean = false,
36 | block: (ConstraintLayout.() -> Unit)? = null
37 | ) = context.constraintLayout(
38 | width,
39 | height,
40 | style,
41 | id,
42 | tag,
43 | foreground,
44 | background,
45 | padding,
46 | visibility,
47 | isSelected,
48 | onClick,
49 | fitsSystemWindows,
50 | block
51 | ).also {
52 | addView(it)
53 | }.applyMargin(margin)
54 |
55 | /**
56 | * 构建约束布局
57 | *
58 | * @param id 需要配置id,用于声明与父布局的关系
59 | */
60 | fun Context.constraintLayout(
61 | width: Int = WRAP_CONTENT,
62 | height: Int = WRAP_CONTENT,
63 | @StyleRes style: Int = 0,
64 | @IdRes id: Int,
65 | tag: Any? = null,
66 | foreground: Drawable? = null,
67 | background: Drawable? = null,
68 | padding: EdgeInsets? = null,
69 | visibility: Int? = null,
70 | isSelected: Boolean? = null,
71 | onClick: View.OnClickListener? = null,
72 | fitsSystemWindows: Boolean = false,
73 |
74 | block: (ConstraintLayout.() -> Unit)? = null
75 | ) = ConstraintLayout(this, null, 0, style).apply {
76 | setup(
77 | width, height, id, tag, foreground, background, padding, visibility, isSelected,
78 | onClick = onClick, fitsSystemWindows = fitsSystemWindows
79 | )
80 | }.attach(block)
81 |
82 | /**
83 | * 声明约束布局的布局属性
84 | *
85 | * 示例:
86 | * layoutParams(
87 | * apply = {
88 | * startToStart = parentId
89 | * endToEnd = parentId
90 | * dimensionRatio = "h, 9:16"
91 | * },
92 | * ) {
93 | * // childView
94 | * }
95 | *
96 | * @param apply 布局规则,通过ConstraintLayout.LayoutParams设置
97 | */
98 | fun ConstraintLayout.layoutParams(
99 | apply: (LayoutParams.() -> Unit)? = null,
100 | block: (ConstraintLayout.() -> T)? = null
101 | ) = attach(block)?.apply {
102 | apply?.let {
103 | layoutParams = when(layoutParams) {
104 | is LayoutParams -> layoutParams as LayoutParams
105 | is ViewGroup.MarginLayoutParams -> LayoutParams(layoutParams as ViewGroup.MarginLayoutParams)
106 | else -> LayoutParams(layoutParams)
107 | }.apply {
108 | it()
109 | }
110 | }
111 | }
112 |
113 | /**
114 | * 声明约束布局的布局属性
115 | *
116 | * @param rules 布局规则,通过Editor工具类传入
117 | *
118 | * 注意:声明view之间的约束关系需要用到各自的id,所以view和parent均需定义id
119 | */
120 | @Deprecated("使用 ConstraintLayout.layoutParams")
121 | fun T.inConstraintLayout(
122 | rules: (T.(ConstraintHelper.Editor) -> Unit)? = null,
123 | ) = apply {
124 | rules?.let {
125 | ConstraintHelper(parent as ConstraintLayout).edit()
126 | .also { editor ->
127 | it(editor)
128 | }.commit()
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/layout/NestedScrollView.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.view.ViewGroup
6 | import androidx.annotation.IdRes
7 | import androidx.core.widget.NestedScrollView
8 | import com.seewo.brick.init.applyMargin
9 | import com.seewo.brick.init.setup
10 | import com.seewo.brick.params.EdgeInsets
11 |
12 | fun T.nestedScrollView(
13 | width: Int = MATCH_PARENT,
14 | height: Int = MATCH_PARENT,
15 |
16 | @IdRes id: Int? = null,
17 | tag: Any? = null,
18 | foreground: Drawable? = null,
19 | background: Drawable? = null,
20 | margin: EdgeInsets? = null,
21 | padding: EdgeInsets? = null,
22 | visibility: Int? = null,
23 | fitsSystemWindows: Boolean = false,
24 |
25 | block: (NestedScrollView.() -> Unit)? = null
26 | ) = context.nestedScrollView(
27 | width, height, id, tag, foreground, background, padding,
28 | visibility, fitsSystemWindows, block
29 | ).also { addView(it) }.applyMargin(margin)
30 |
31 | fun Context.nestedScrollView(
32 | width: Int = MATCH_PARENT,
33 | height: Int = MATCH_PARENT,
34 |
35 | @IdRes id: Int? = null,
36 | tag: Any? = null,
37 | foreground: Drawable? = null,
38 | background: Drawable? = null,
39 | padding: EdgeInsets? = null,
40 | visibility: Int? = null,
41 | fitsSystemWindows: Boolean = false,
42 |
43 | block: (NestedScrollView.() -> Unit)? = null
44 | ) = NestedScrollView(this).apply {
45 | setup(
46 | width, height, id, tag, foreground, background, padding, visibility,
47 | fitsSystemWindows = fitsSystemWindows
48 | )
49 | }.attach(block)
50 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/layout/RelativeLayoutKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.widget.RelativeLayout
8 | import androidx.annotation.IdRes
9 | import androidx.annotation.StyleRes
10 | import com.seewo.brick.init.applyMargin
11 | import com.seewo.brick.init.setup
12 | import com.seewo.brick.params.EdgeInsets
13 |
14 |
15 | /**
16 | * 构建相对布局
17 | */
18 | fun ViewGroup.relativeLayout(
19 | width: Int = WRAP_CONTENT,
20 | height: Int = WRAP_CONTENT,
21 |
22 | @StyleRes style: Int = 0,
23 | @IdRes id: Int? = null,
24 | tag: Any? = null,
25 | foreground: Drawable? = null,
26 | background: Drawable? = null,
27 | margin: EdgeInsets? = null,
28 | padding: EdgeInsets? = null,
29 | visibility: Int? = null,
30 | isSelected: Boolean? = null,
31 | onClick: View.OnClickListener? = null,
32 | fitsSystemWindows: Boolean = false,
33 |
34 | block: (RelativeLayout.() -> Unit)? = null
35 | ) = context.relativeLayout(
36 | width,
37 | height,
38 | style,
39 | id,
40 | tag,
41 | foreground,
42 | background,
43 | padding,
44 | visibility,
45 | isSelected,
46 | onClick,
47 | fitsSystemWindows,
48 | block
49 | ).also {
50 | addView(it)
51 | }.applyMargin(margin)
52 |
53 | /**
54 | * 构建相对布局
55 | */
56 | fun Context.relativeLayout(
57 | width: Int = WRAP_CONTENT,
58 | height: Int = WRAP_CONTENT,
59 |
60 | @StyleRes style: Int = 0,
61 | @IdRes id: Int? = null,
62 | tag: Any? = null,
63 | foreground: Drawable? = null,
64 | background: Drawable? = null,
65 | padding: EdgeInsets? = null,
66 | visibility: Int? = null,
67 | isSelected: Boolean? = null,
68 | onClick: View.OnClickListener? = null,
69 | fitsSystemWindows: Boolean = false,
70 |
71 | block: (RelativeLayout.() -> Unit)? = null
72 | ) = RelativeLayout(this, null, 0, style).apply {
73 | setup(
74 | width, height, id, tag, foreground, background, padding, visibility, isSelected,
75 | onClick = onClick, fitsSystemWindows = fitsSystemWindows
76 | )
77 | }.attach(block)
78 |
79 | /**
80 | * 声明相对布局的布局属性
81 | */
82 | fun RelativeLayout.layoutParams(
83 | margins: EdgeInsets? = null,
84 | rules: (RelativeLayout.LayoutParams.() -> Unit)? = null,
85 | block: (RelativeLayout.() -> View)? = null
86 | ) = attach(block)?.apply {
87 | layoutParams = when(layoutParams) {
88 | is RelativeLayout.LayoutParams -> layoutParams as RelativeLayout.LayoutParams
89 | is ViewGroup.MarginLayoutParams -> RelativeLayout.LayoutParams(layoutParams as ViewGroup.MarginLayoutParams)
90 | else -> RelativeLayout.LayoutParams(layoutParams)
91 | }.apply {
92 | margins?.let { setMargins(it.start, it.top, it.end, it.bottom) }
93 | rules?.invoke(this)
94 | }
95 | }
96 |
97 | /**
98 | * 声明相对布局的布局属性
99 | */
100 | @Deprecated("使用 RelativeLayout.layoutParams")
101 | fun T.inRelativeLayout(
102 | margins: EdgeInsets? = null,
103 | rules: (RelativeLayout.LayoutParams.() -> Unit)? = null,
104 | ) = apply {
105 | layoutParams = when(layoutParams) {
106 | is RelativeLayout.LayoutParams -> layoutParams as RelativeLayout.LayoutParams
107 | is ViewGroup.MarginLayoutParams -> RelativeLayout.LayoutParams(layoutParams as ViewGroup.MarginLayoutParams)
108 | else -> RelativeLayout.LayoutParams(layoutParams)
109 | }.apply {
110 | margins?.let { setMargins(it.start, it.top, it.end, it.bottom) }
111 | rules?.invoke(this)
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/layout/Toolbar.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.res.ColorStateList
4 | import android.graphics.drawable.Drawable
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.ColorInt
8 | import androidx.annotation.IdRes
9 | import androidx.annotation.MenuRes
10 | import androidx.annotation.StyleRes
11 | import androidx.appcompat.widget.Toolbar
12 | import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener
13 | import com.google.android.material.appbar.CollapsingToolbarLayout
14 | import com.seewo.brick.init.setup
15 | import com.seewo.brick.params.EdgeInsets
16 |
17 | /**
18 | * 注意:用于 [CollapsingToolbarLayout] 的 [Toolbar] 有较多限制,部分属性无法生效
19 | */
20 | fun T.toolbar(
21 | width: Int = MATCH_PARENT,
22 | height: Int = WRAP_CONTENT,
23 | @IdRes id: Int? = null,
24 | navigation: ToolbarNavigation? = null,
25 | logo: Drawable? = null,
26 | title: String? = null,
27 | titleStyle: ToolbarTitleStyle? = null,
28 | titleMargins: EdgeInsets? = null,
29 | subTitle: String? = null,
30 | subTitleStyle: ToolbarTitleStyle? = null,
31 | @MenuRes menu: Int? = null,
32 | onMenuItemClick: OnMenuItemClickListener? = null,
33 | block: (Toolbar.() -> Unit)? = null,
34 | ) = Toolbar(context).apply {
35 | setup(width, height, id = id)
36 | logo?.let { this.logo = it }
37 | title?.let { this.title = it }
38 | titleStyle?.run {
39 | textAppearance?.let { setTitleTextAppearance(context, it) }
40 | textColor?.let { setTitleTextColor(it) }
41 | textColors?.let { setTitleTextColor(it) }
42 | }
43 | titleMargins?.let { setTitleMargin(it.start, it.top, it.end, it.bottom) }
44 | subTitle?.let { this.subtitle = it }
45 | subTitleStyle?.run {
46 | textAppearance?.let { setSubtitleTextAppearance(context, it) }
47 | textColor?.let { setSubtitleTextColor(it) }
48 | textColors?.let { setSubtitleTextColor(it) }
49 | }
50 | navigation?.run {
51 | icon?.let { navigationIcon = it }
52 | onClick?.let { setNavigationOnClickListener(it) }
53 | }
54 | menu?.let {
55 | inflateMenu(it)
56 | onMenuItemClick?.let { listener -> setOnMenuItemClickListener(listener) }
57 | }
58 | }.also { addView(it) }.attach(block)
59 |
60 | class ToolbarTitleStyle(
61 | @StyleRes val textAppearance: Int? = null,
62 | @ColorInt val textColor: Int? = null,
63 | val textColors: ColorStateList? = null,
64 | )
65 |
66 | class ToolbarNavigation(
67 | val icon: Drawable? = null,
68 | val onClick: View.OnClickListener? = null,
69 | )
70 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/util/CommonKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.activity.ComponentActivity
9 | import androidx.activity.viewModels
10 | import androidx.annotation.FloatRange
11 | import androidx.annotation.IdRes
12 | import androidx.annotation.LayoutRes
13 | import androidx.lifecycle.AndroidViewModel
14 | import com.seewo.brick.BrickUI
15 | import com.seewo.brick.init.applyMargin
16 | import com.seewo.brick.init.setup
17 | import com.seewo.brick.params.EdgeInsets
18 |
19 |
20 | const val MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT
21 | const val WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT
22 |
23 | /**
24 | * 通过代码构造View时,可以通过init迅速传入宽高
25 | */
26 | fun View.init(width: Int = WRAP_CONTENT, height: Int = WRAP_CONTENT) {
27 | layoutParams = ViewGroup.LayoutParams(width, height)
28 | }
29 |
30 | /**
31 | * 普通View嵌入声明
32 | * 包裹普通View,嵌入到BrickUI中
33 | *
34 | * 如果View已经有父布局了,不要使用本函数嵌入,否则会抛以下异常
35 | * java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
36 | */
37 | @Deprecated("使用 T.brick() 代替")
38 | inline fun T.view(
39 | block: T.() -> View
40 | ): View = block().also { addView(it) }
41 |
42 | /**
43 | * 包裹普通View嵌入BrickUI声明式布局中,并可定义一些布局属性
44 | */
45 | fun Context.brick(
46 | width: Int = WRAP_CONTENT, height: Int = WRAP_CONTENT,
47 | @IdRes id: Int? = null,
48 | tag: Any? = null,
49 | foreground: Drawable? = null,
50 | background: Drawable? = null,
51 | padding: EdgeInsets? = null,
52 | visibility: Int? = null,
53 | isSelected: Boolean? = null,
54 | isEnabled: Boolean? = null,
55 | onClick: View.OnClickListener? = null,
56 | fitsSystemWindows: Boolean? = null,
57 | block: Context.() -> View
58 | ): View = block().apply {
59 | setup(width, height, id, tag, foreground, background, padding, visibility, isSelected, isEnabled, onClick, fitsSystemWindows)
60 | }
61 |
62 | /**
63 | * 包裹普通View嵌入BrickUI声明式布局中,并可定义一些布局属性
64 | *
65 | * 如果View已经有父布局了,不要使用本函数嵌入,否则会抛以下异常
66 | * java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
67 | */
68 | fun T.brick(
69 | width: Int = WRAP_CONTENT, height: Int = WRAP_CONTENT,
70 | @IdRes id: Int? = null,
71 | tag: Any? = null,
72 | foreground: Drawable? = null,
73 | background: Drawable? = null,
74 | padding: EdgeInsets? = null,
75 | visibility: Int? = null,
76 | isSelected: Boolean? = null,
77 | isEnabled: Boolean? = null,
78 | onClick: View.OnClickListener? = null,
79 | fitsSystemWindows: Boolean? = null,
80 | margin: EdgeInsets? = null,
81 | block: T.() -> View
82 | ): View = block().apply {
83 | setup(width, height, id, tag, foreground, background, padding, visibility, isSelected, isEnabled, onClick, fitsSystemWindows)
84 | }.also {
85 | addView(it)
86 | }.applyMargin(margin)
87 |
88 | /**
89 | * 获取Application的Context
90 | */
91 | val applicationContext: Context
92 | get() = BrickUI.applicationContext
93 |
94 | /**
95 | * inflate Layout资源
96 | */
97 | fun Context.inflate(
98 | @LayoutRes resource: Int,
99 | root: ViewGroup?,
100 | attachToRoot: Boolean = root != null
101 | ) = LayoutInflater.from(this).inflate(resource, root, attachToRoot)
102 |
103 | /**
104 | * 获取Activity的ViewModel
105 | *
106 | * 注意:preview中使用这个方法会抛异常,需要用到IDE预览的,可以使用Context.activityViewModelOrNull()
107 | */
108 | inline fun Context.activityViewModel(): VM =
109 | (this as ComponentActivity).viewModels().value
110 |
111 | /**
112 | * 获取Activity的ViewModel
113 | */
114 | inline fun Context.activityViewModelOrNull(): VM? =
115 | (this as? ComponentActivity)?.viewModels()?.value
116 |
117 | /**
118 | * 对一个ColorInt设置不透明度
119 | * @param alpha 不透明度,取值0到1f
120 | */
121 | fun Int.withAlpha(@FloatRange(from = 0.0, to = 1.0) alpha: Float): Int =
122 | this and 0xFFFFFF or ((alpha * 255.0f).toInt() shl 24)
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/util/ResourceKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorInflater
5 | import android.graphics.drawable.ColorDrawable
6 | import android.graphics.drawable.Drawable
7 | import androidx.annotation.AnimatorRes
8 | import androidx.annotation.ColorInt
9 | import androidx.annotation.ColorRes
10 | import androidx.annotation.DimenRes
11 | import androidx.annotation.StringRes
12 | import com.seewo.brick.BrickUI
13 |
14 |
15 | /**
16 | * dp转px
17 | */
18 | val Double.dp: Int
19 | get() = this.toFloat().dp
20 |
21 | /**
22 | * dp转px
23 | */
24 | val Float.dp: Int
25 | get() = BrickUI.dipToPixel(this)
26 |
27 | /**
28 | * dp转px
29 | */
30 | val Int.dp: Int
31 | get() = this.toFloat().dp
32 |
33 | /**
34 | * sp转px
35 | */
36 | val Double.sp: Int
37 | get() = this.toFloat().sp
38 |
39 | /**
40 | * sp转px
41 | */
42 | val Float.sp: Int
43 | get() = BrickUI.spToPixel(this)
44 |
45 | /**
46 | * sp转px
47 | */
48 | val Int.sp: Int
49 | get() = this.toFloat().sp
50 |
51 | /**
52 | * 资源id转drawable
53 | */
54 | val @receiver:DimenRes Int.drawable: Drawable?
55 | get() = BrickUI.drawable(this)
56 |
57 | /**
58 | * 资源id转颜色类型drawable
59 | */
60 | val @receiver:ColorRes Int.colorDrawable: Drawable?
61 | get() = runCatching { ColorDrawable(color) }.getOrNull()
62 |
63 | /**
64 | * 资源id转color
65 | */
66 | @get:ColorInt
67 | val @receiver:ColorRes Int.color: Int
68 | get() = BrickUI.color(this)
69 |
70 | /**
71 | * 资源id转String。如需携带参数,可使用 Int.getString(vararg params: Any)
72 | */
73 | val @receiver:StringRes Int.string: String
74 | get() = BrickUI.string(this)
75 |
76 | /**
77 | * 资源id转String,可携带参数
78 | */
79 | fun @receiver:StringRes Int.getString(vararg params: Any): String = BrickUI.string(this, *params)
80 |
81 | /**
82 | * 资源id转dimension
83 | */
84 | val @receiver:DimenRes Int.dimension: Int
85 | get() = BrickUI.dimension(this)
86 |
87 | val @receiver:AnimatorRes Int.animator: Animator
88 | get() = AnimatorInflater.loadAnimator(applicationContext, this)
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/util/ViewClipKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.graphics.Outline
4 | import android.graphics.Rect
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import android.view.ViewOutlineProvider
8 |
9 | /**
10 | * View 矩形/圆角矩形裁剪
11 | *
12 | * @param rect 裁剪区域
13 | * @param radius 裁剪圆角
14 | *
15 | * 注意:关闭硬件加速将无法生效
16 | */
17 | fun T.roundRectClip(
18 | rect: Rect? = null,
19 | radius: Int? = null,
20 | block: T.() -> View
21 | ) = block().apply {
22 | outlineProvider = object : ViewOutlineProvider() {
23 | override fun getOutline(view: View, outline: Outline?) {
24 | val finalRect = rect ?: Rect(0, 0, view.width, view.height)
25 | outline?.setRoundRect(finalRect, (radius ?: 0).toFloat())
26 | }
27 | }
28 | clipToOutline = true
29 | }
30 |
31 | /**
32 | * View 圆形/椭圆形裁剪
33 | *
34 | * @param rect 裁剪区域
35 | *
36 | * 注意:关闭硬件加速将无法生效
37 | */
38 | fun T.ovalClip(
39 | rect: Rect? = null,
40 | block: T.() -> View
41 | ) = block().apply {
42 | outlineProvider = object : ViewOutlineProvider() {
43 | override fun getOutline(view: View, outline: Outline?) {
44 | val finalRect = rect ?: Rect(0, 0, view.width, view.height)
45 | outline?.setOval(finalRect)
46 | }
47 | }
48 | clipToOutline = true
49 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/widget/FragmentKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import androidx.lifecycle.Lifecycle
6 | import com.seewo.brick.view.BrickFragment
7 |
8 | /**
9 | * 声明式构造Fragment
10 | *
11 | * @param onStateChanged 指Fragment独有的状态变化 onHiddenChanged setUserVisibleHint,实际状态通过相关方法获取
12 | * @param lifecycleHandler 用于监听Fragment的生命周期
13 | */
14 | fun Context.fragment(
15 | onStateChanged: ((BrickFragment) -> Unit)? = null,
16 | lifecycleHandler: (BrickFragment.(Lifecycle) -> Unit)? = null,
17 | block: Context.() -> View,
18 | ) = BrickFragment(onStateChanged, lifecycleHandler, block)
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/ktx/widget/NestedScrollableKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx // 包名别改
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import android.view.ViewGroup
6 | import androidx.annotation.IdRes
7 | import com.seewo.brick.init.applyMargin
8 | import com.seewo.brick.init.setup
9 | import com.seewo.brick.params.EdgeInsets
10 | import com.seewo.brick.view.NestedScrollableHost
11 |
12 | /**
13 | * 解决ViewPager2等的嵌套导致的滚动冲突
14 | */
15 | fun Context.nestedScrollableChild(
16 | width: Int, height: Int,
17 | @IdRes id: Int? = null,
18 | tag: Any? = null,
19 | padding: EdgeInsets? = null,
20 | visibility: Int? = null,
21 | fitsSystemWindows: Boolean = false,
22 | block: NestedScrollableHost.() -> View,
23 | ) = NestedScrollableHost(this).apply {
24 | setup(
25 | width, height, id, tag, padding = padding, visibility = visibility,
26 | fitsSystemWindows = fitsSystemWindows,
27 | )
28 | this.block()
29 | }
30 |
31 | /**
32 | * 解决ViewPager2等的嵌套导致的滚动冲突
33 | */
34 | fun ViewGroup.nestedScrollableChild(
35 | width: Int, height: Int,
36 | @IdRes id: Int? = null,
37 | tag: Any? = null,
38 | margin: EdgeInsets? = null,
39 | padding: EdgeInsets? = null,
40 | visibility: Int? = null,
41 | fitsSystemWindows: Boolean = false,
42 | block: NestedScrollableHost.() -> View,
43 | ) = context.nestedScrollableChild(
44 | width, height, id, tag, padding, visibility, fitsSystemWindows, block
45 | ).also { addView(it) }.applyMargin(margin)
46 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/CollapseMode.java:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params;
2 |
3 | import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
4 | import static com.seewo.brick.params.CollapseMode.COLLAPSE_MODE_OFF;
5 | import static com.seewo.brick.params.CollapseMode.COLLAPSE_MODE_PARALLAX;
6 | import static com.seewo.brick.params.CollapseMode.COLLAPSE_MODE_PIN;
7 |
8 | import androidx.annotation.IntDef;
9 | import androidx.annotation.RestrictTo;
10 |
11 | import com.google.android.material.appbar.CollapsingToolbarLayout;
12 |
13 | import java.lang.annotation.Retention;
14 | import java.lang.annotation.RetentionPolicy;
15 |
16 |
17 | @RestrictTo(LIBRARY_GROUP)
18 | @IntDef({COLLAPSE_MODE_OFF, COLLAPSE_MODE_PIN, COLLAPSE_MODE_PARALLAX})
19 | @Retention(RetentionPolicy.SOURCE)
20 | public @interface CollapseMode {
21 | int COLLAPSE_MODE_OFF = CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_OFF;
22 | int COLLAPSE_MODE_PARALLAX = CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PARALLAX;
23 | int COLLAPSE_MODE_PIN = CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN;
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/CompoundDrawables.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params
2 |
3 | import android.graphics.drawable.Drawable
4 |
5 | class CompoundDrawables(
6 | val start: Drawable? = null,
7 | val top: Drawable? = null,
8 | val end: Drawable? = null,
9 | val bottom: Drawable? = null,
10 | )
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/CornerRadius.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params
2 |
3 | class CornerRadius private constructor(
4 | val leftTop: Float,
5 | val rightTop: Float,
6 | val rightBottom: Float,
7 | val leftBottom: Float,
8 | ) {
9 | val toArray: FloatArray
10 | get() = floatArrayOf(
11 | leftTop, leftTop, rightTop, rightTop,
12 | rightBottom, rightBottom, leftBottom, leftBottom,
13 | )
14 |
15 | companion object {
16 | @JvmStatic
17 | fun only(
18 | leftTop: Int = 0,
19 | rightTop: Int = 0,
20 | rightBottom: Int = 0,
21 | leftBottom: Int = 0,
22 | ): CornerRadius = CornerRadius(
23 | leftTop.toFloat(), rightTop.toFloat(), rightBottom.toFloat(), leftBottom.toFloat())
24 |
25 | @JvmStatic
26 | fun zero() = only()
27 |
28 | @JvmStatic
29 | fun all(radius: Int) = only(radius, radius, radius, radius)
30 | }
31 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/EdgeInsets.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params
2 |
3 | import kotlin.math.abs
4 |
5 | class EdgeInsets private constructor(
6 | val start: Int,
7 | val top: Int,
8 | val end: Int,
9 | val bottom: Int,
10 | ) {
11 |
12 | val height = abs(bottom - top)
13 | val width = abs(end - start)
14 |
15 | companion object {
16 | @JvmStatic
17 | fun all(value: Int) = EdgeInsets(value, value, value, value)
18 |
19 | @JvmStatic
20 | val zero: EdgeInsets
21 | get() = EdgeInsets(0, 0, 0, 0)
22 |
23 | @JvmStatic
24 | fun only(
25 | start: Int = 0,
26 | top: Int = 0,
27 | end: Int = 0,
28 | bottom: Int = 0,
29 | ) = EdgeInsets(start, top, end, bottom)
30 |
31 | @JvmStatic
32 | fun symmetric(
33 | vertical: Int = 0,
34 | horizontal: Int = 0,
35 | ) = EdgeInsets(horizontal, vertical, horizontal, vertical)
36 | }
37 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/RecyclerItemData.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params
2 |
3 | interface RecyclerItemData {
4 | /**
5 | * 比较两个RecyclerItemData是否为同一个item(如对应同一个id)
6 | * 如果是同一项,则如果不相等,认为是同一项需要更新内容;否则认为不是同一项
7 | */
8 | fun areSameItem(out: Any?): Boolean
9 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/params/Shadow.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.params
2 |
3 | import android.graphics.Color
4 | import androidx.annotation.ColorInt
5 | import com.seewo.brick.ktx.dp
6 |
7 | /**
8 | * 阴影参数设置
9 | *
10 | * @param color 阴影颜色
11 | * @param blur 阴影模糊半径
12 | * @param offsetX 阴影横向偏移
13 | * @param offsetY 阴影纵向偏移
14 | */
15 | class Shadow(
16 | @ColorInt val color: Int = Color.parseColor("#5F333333"),
17 | val blur: Int = 3.dp,
18 | val offsetX: Int = 0,
19 | val offsetY: Int = 0,
20 | )
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/span/CenterAlignImageSpan.java:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.span;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.graphics.drawable.Drawable;
9 | import android.text.style.ImageSpan;
10 |
11 | import androidx.annotation.NonNull;
12 |
13 | public class CenterAlignImageSpan extends ImageSpan {
14 |
15 | public CenterAlignImageSpan(@NonNull Drawable d) {
16 | super(d);
17 | }
18 |
19 | public CenterAlignImageSpan(@NonNull Context context, @NonNull Bitmap bitmap) {
20 | super(context, bitmap);
21 | }
22 |
23 | public CenterAlignImageSpan(@NonNull Context context, int resourceId) {
24 | super(context, resourceId);
25 | }
26 |
27 | @Override
28 | public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
29 | Drawable b = getDrawable();
30 | Paint.FontMetricsInt fm = paint.getFontMetricsInt();
31 | int transY = y + (fm.descent + fm.ascent) / 2 - b.getBounds().height() / 2;//计算y方向的位移
32 | canvas.save();
33 | canvas.translate(x, transY);//绘制图片位移一段距离
34 | b.draw(canvas);
35 | canvas.restore();
36 | }
37 | /**
38 | * 重写getSize方法,只有重写该方法后,才能保证不论是图片大于文字还是文字大于图片,都能实现中间对齐
39 | */
40 | public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
41 | Drawable d = getDrawable();
42 | Rect rect = d.getBounds();
43 | if (fm != null) {
44 | Paint.FontMetricsInt fmPaint = paint.getFontMetricsInt();
45 | int fontHeight = fmPaint.bottom - fmPaint.top;
46 | int drHeight = rect.bottom - rect.top;
47 |
48 | int top = drHeight / 2 - fontHeight / 4;
49 | int bottom = drHeight / 2 + fontHeight / 4;
50 |
51 | fm.ascent = -bottom;
52 | fm.top = -bottom;
53 | fm.bottom = top;
54 | fm.descent = top;
55 | }
56 | return rect.right;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/BrickFragment.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import android.os.Bundle
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.fragment.app.Fragment
9 | import androidx.lifecycle.Lifecycle
10 |
11 | /**
12 | * @param onStateChanged 指Fragment独有的状态变化 onHiddenChanged setUserVisibleHint
13 | * @param lifecycleHandler 用于监听Fragment的生命周期
14 | */
15 | class BrickFragment(
16 | private val onStateChanged: ((BrickFragment) -> Unit)? = null,
17 | private val lifecycleHandler: (BrickFragment.(Lifecycle) -> Unit)? = null,
18 | private val block: Context.() -> View,
19 | ): Fragment() {
20 | override fun onCreateView(
21 | inflater: LayoutInflater,
22 | container: ViewGroup?,
23 | savedInstanceState: Bundle?
24 | ): View = requireContext().block().apply {
25 | lifecycleHandler?.let {
26 | it(lifecycle)
27 | }
28 | }
29 |
30 | override fun onHiddenChanged(hidden: Boolean) {
31 | super.onHiddenChanged(hidden)
32 | onStateChanged?.invoke(this)
33 | }
34 |
35 | override fun setUserVisibleHint(isVisibleToUser: Boolean) {
36 | super.setUserVisibleHint(isVisibleToUser)
37 | onStateChanged?.invoke(this)
38 | }
39 |
40 | val isConfirmedVisible: Boolean
41 | get() = isResumed && isVisible && userVisibleHint
42 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/DividerDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import android.graphics.Rect
8 | import android.view.View
9 | import androidx.recyclerview.widget.LinearLayoutManager
10 | import androidx.recyclerview.widget.RecyclerView
11 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration
12 | import com.seewo.brick.ktx.dp
13 | import com.seewo.brick.params.EdgeInsets
14 |
15 | class DividerDecoration(
16 | context: Context,
17 | orientation: Int? = null,
18 | dividerHeight: Int? = null,
19 | dividerColor: Int? = null,
20 | padding: EdgeInsets? = null,
21 | ) : ItemDecoration() {
22 | private val mPaint: Paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
23 | color = dividerColor ?: Color.WHITE
24 | style = Paint.Style.FILL
25 | }
26 | private val mOrientation: Int = orientation ?: LinearLayoutManager.VERTICAL
27 | private val mDividerHeight: Int = dividerHeight ?: 1.dp
28 | private val mPadding: EdgeInsets = padding ?: EdgeInsets.zero
29 | companion object {
30 | private val ATTRS = intArrayOf(android.R.attr.listDivider) //使用系统自带的listDivider
31 | }
32 |
33 | init {
34 | require(!(mOrientation != LinearLayoutManager.VERTICAL && mOrientation != LinearLayoutManager.HORIZONTAL)) { "请输入正确的参数!" }
35 | val a = context.obtainStyledAttributes(ATTRS) //使用TypeArray加载该系统资源
36 | a.recycle() //缓存
37 | }
38 |
39 | //获取分割线尺寸
40 | override fun getItemOffsets(
41 | outRect: Rect,
42 | view: View,
43 | parent: RecyclerView,
44 | state: RecyclerView.State
45 | ) {
46 | if (mOrientation == LinearLayoutManager.VERTICAL) {
47 | outRect.set(0, 0, 0, mDividerHeight + mPadding.height)
48 | } else {
49 | outRect.set(0, 0, mDividerHeight + mPadding.width, 0)
50 | }
51 | }
52 |
53 | //绘制分割线
54 | override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
55 | super.onDraw(c, parent, state)
56 | if (mOrientation == LinearLayoutManager.VERTICAL) {
57 | drawVertical(c, parent)
58 | } else {
59 | drawHorizontal(c, parent)
60 | }
61 | }
62 |
63 | //绘制横向布局 item 分割线
64 | private fun drawHorizontal(canvas: Canvas, parent: RecyclerView) {
65 | val top = parent.paddingTop + mPadding.top
66 | val bottom = parent.measuredHeight - parent.paddingBottom - mPadding.bottom
67 | val childSize = parent.childCount
68 | for (i in 0 until childSize - 1) {
69 | val child = parent.getChildAt(i)
70 | val layoutParams = child.layoutParams as RecyclerView.LayoutParams
71 | val left = child.right + layoutParams.rightMargin + mPadding.start
72 | val right = left + mDividerHeight
73 | canvas.drawRect(
74 | left.toFloat(),
75 | top.toFloat(),
76 | right.toFloat(),
77 | bottom.toFloat(),
78 | mPaint
79 | )
80 | }
81 | }
82 |
83 | //绘制纵向布局 item 分割线
84 | private fun drawVertical(canvas: Canvas, parent: RecyclerView) {
85 | val left = parent.paddingLeft + mPadding.start //获取分割线的左边距,即RecyclerView的padding值
86 | val right = parent.measuredWidth - parent.paddingRight - mPadding.end //分割线右边距
87 | val childSize = parent.childCount
88 | //遍历所有item view,为它们的下方绘制分割线
89 | for (i in 0 until childSize - 1) {
90 | val child = parent.getChildAt(i)
91 | val layoutParams = child.layoutParams as RecyclerView.LayoutParams
92 | val top = child.bottom + layoutParams.bottomMargin + mPadding.top
93 | val bottom = top + mDividerHeight
94 | canvas.drawRect(
95 | left.toFloat(),
96 | top.toFloat(),
97 | right.toFloat(),
98 | bottom.toFloat(),
99 | mPaint
100 | )
101 | }
102 | }
103 |
104 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/FixDurationScroller.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import android.view.animation.AccelerateDecelerateInterpolator
5 | import android.widget.Scroller
6 | import androidx.viewpager.widget.ViewPager
7 |
8 | class FixDurationScroller(context: Context, private val duration: Int): Scroller(context, AccelerateDecelerateInterpolator()) {
9 | override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int) {
10 | super.startScroll(startX, startY, dx, dy, duration)
11 | }
12 |
13 | override fun startScroll(startX: Int, startY: Int, dx: Int, dy: Int, duration: Int) {
14 | super.startScroll(startX, startY, dx, dy, this.duration)
15 | }
16 | }
17 |
18 | fun ViewPager.trySetDuration(duration: Int) {
19 | try {
20 | val scrollerField = ViewPager::class.java.getDeclaredField("mScroller")
21 | scrollerField.isAccessible = true
22 | val scroller = FixDurationScroller(context, duration)
23 | scrollerField.set(this, scroller)
24 | } catch (e: Exception) {
25 | e.printStackTrace()
26 | }
27 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/GridSpaceDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.graphics.Rect
4 | import android.view.View
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import androidx.recyclerview.widget.RecyclerView
7 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration
8 |
9 | class GridSpaceDecoration(
10 | private val columnSpace: Int,
11 | private val rowSpace: Int,
12 | ) : ItemDecoration() {
13 |
14 | override fun getItemOffsets(
15 | outRect: Rect,
16 | view: View,
17 | parent: RecyclerView,
18 | state: RecyclerView.State
19 | ) {
20 | val layoutManager = parent.layoutManager
21 |
22 | if (layoutManager is GridLayoutManager) {
23 | val horizontalItemSpace =
24 | columnSpace * (layoutManager.spanCount - 1) / layoutManager.spanCount
25 | val rowCount = (layoutManager.itemCount - 1) / layoutManager.spanCount + 1
26 | val verticalItemSpace = rowSpace * (rowCount - 1) / rowCount
27 | val position = parent.getChildAdapterPosition(view)
28 | when (position % layoutManager.spanCount) {
29 | 0 -> {
30 | outRect.right = horizontalItemSpace
31 | }
32 | layoutManager.spanCount - 1 -> {
33 | outRect.left = horizontalItemSpace
34 | }
35 | else -> {
36 | outRect.left = horizontalItemSpace / 2
37 | outRect.right = horizontalItemSpace / 2
38 | }
39 | }
40 | when (position / layoutManager.spanCount) {
41 | 0 -> {
42 | outRect.bottom = verticalItemSpace
43 | }
44 | (layoutManager.itemCount - 1) / layoutManager.spanCount -> {
45 | outRect.top = verticalItemSpace
46 | }
47 | else -> {
48 | outRect.bottom = verticalItemSpace / 2
49 | outRect.top = verticalItemSpace / 2
50 | }
51 | }
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/LimitLinesFlexboxLayout.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import com.google.android.flexbox.FlexLine
5 | import com.google.android.flexbox.FlexboxLayout
6 |
7 | class LimitLinesFlexboxLayout(context: Context): FlexboxLayout(context) {
8 | private var mMaxLine = NOT_SET
9 | override fun setMaxLine(maxLine: Int) {
10 | mMaxLine = maxLine
11 | }
12 |
13 | override fun getMaxLine(): Int {
14 | return NOT_SET
15 | }
16 |
17 | override fun getFlexLinesInternal(): MutableList {
18 | val flexLines = super.getFlexLinesInternal()
19 | if (mMaxLine > 0 && flexLines.size > mMaxLine) {
20 | flexLines.subList(mMaxLine, flexLines.size).clear()
21 | }
22 | return flexLines
23 | }
24 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/ShadowLayout.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import android.graphics.Rect
8 | import android.graphics.RectF
9 | import android.os.Build
10 | import android.util.AttributeSet
11 | import android.view.View
12 | import android.widget.FrameLayout
13 | import com.seewo.brick.ktx.dp
14 | import kotlin.math.max
15 |
16 |
17 | class ShadowLayout : FrameLayout {
18 |
19 | var customBackgroundColor: Int = Color.WHITE
20 | set(value) {
21 | field = value
22 | postInvalidate()
23 | }
24 |
25 | var backgroundRadius: Float = 0f
26 | set(value) {
27 | field = value
28 | postInvalidate()
29 | }
30 |
31 | var shadowOffsetX = 0f
32 | set(value) {
33 | field = value
34 | updatePaint()
35 | updateRect()
36 | requestLayout()
37 | }
38 |
39 | var shadowOffsetY = 0f
40 | set(value) {
41 | field = value
42 | updatePaint()
43 | updateRect()
44 | requestLayout()
45 | }
46 | var shadowColor = Color.BLACK
47 | set(value) {
48 | field = value
49 | updatePaint()
50 | postInvalidate()
51 | }
52 |
53 | var shadowRadius = 2.dp.toFloat()
54 | set(value) {
55 | field = value
56 | updateRect()
57 | updatePaint()
58 | requestLayout()
59 | }
60 |
61 | private val backgroundRect = RectF()
62 | private val backgroundPaint = Paint()
63 | private val initPaddingRect = Rect()
64 |
65 | constructor(context: Context) : this(context, null)
66 | constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
67 | constructor(context: Context, attrs: AttributeSet?, style: Int) : super(context, attrs, style) {
68 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
69 | setLayerType(View.LAYER_TYPE_SOFTWARE, null)
70 | }
71 | setWillNotDraw(false)
72 | updatePaint()
73 | initPaddingRect.set(paddingStart, paddingTop, paddingEnd, paddingBottom)
74 | }
75 |
76 | override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
77 | updateRect()
78 | super.onLayout(changed, left, top, right, bottom)
79 | }
80 |
81 | private fun updatePaint() {
82 | backgroundPaint.apply {
83 | color = customBackgroundColor
84 | setShadowLayer(shadowRadius, shadowOffsetX, shadowOffsetY, shadowColor)
85 | }
86 | }
87 |
88 | private fun updateRect() {
89 | setPadding(
90 | (initPaddingRect.left + max((shadowRadius - shadowOffsetX), 0f)).toInt(),
91 | (initPaddingRect.top + max((shadowRadius - shadowOffsetY), 0f)).toInt(),
92 | (shadowRadius + initPaddingRect.right + shadowOffsetX).toInt(),
93 | (shadowRadius + initPaddingRect.bottom + shadowOffsetY).toInt(),
94 | )
95 | if (width == 0 || height == 0) return
96 | backgroundRect.set(
97 | paddingStart.toFloat(),
98 | paddingTop.toFloat(),
99 | (width - paddingEnd).toFloat(),
100 | (height - paddingBottom).toFloat()
101 | )
102 | }
103 |
104 | override fun onDraw(canvas: Canvas?) {
105 | canvas?.drawRoundRect(backgroundRect, backgroundRadius, backgroundRadius, backgroundPaint)
106 | super.onDraw(canvas)
107 | }
108 | }
--------------------------------------------------------------------------------
/core/src/main/java/com/seewo/brick/view/WindowInsetsFrameLayout.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.view
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.View
6 | import android.view.WindowInsets
7 | import android.widget.FrameLayout
8 |
9 | class WindowInsetsFrameLayout @JvmOverloads constructor(
10 | context: Context?,
11 | attrs: AttributeSet? = null,
12 | defStyleAttr: Int = 0,
13 | defStyleRes: Int = 0,
14 | ) : FrameLayout(
15 | context!!, attrs, defStyleAttr, defStyleRes
16 | ) {
17 | override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
18 | val childCount = childCount
19 | for (index in 0 until childCount) {
20 | getChildAt(index).dispatchApplyWindowInsets(insets)
21 | }
22 | return insets
23 | }
24 |
25 | override fun dispatchApplyWindowInsets(insets: WindowInsets): WindowInsets {
26 | //重写分发方法,不判断是否消费
27 | for (index in 0 until childCount) {
28 | try {
29 | getChildAt(index).dispatchApplyWindowInsets(insets)
30 | } catch (e: Throwable) {
31 | e.printStackTrace()
32 | }
33 | }
34 | return insets
35 | }
36 |
37 | init {
38 | setOnHierarchyChangeListener(object : OnHierarchyChangeListener {
39 | override fun onChildViewAdded(parent: View, child: View) {
40 | requestApplyInsets()
41 | }
42 |
43 | override fun onChildViewRemoved(parent: View, child: View) {}
44 | })
45 | }
46 | }
--------------------------------------------------------------------------------
/core/src/main/res/animator/scale_with_alpha.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
16 |
17 |
22 |
--------------------------------------------------------------------------------
/doc/BrickUIPreview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/BrickUIPreview.png
--------------------------------------------------------------------------------
/doc/CvteCall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/CvteCall.png
--------------------------------------------------------------------------------
/doc/QRCodeDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/QRCodeDemo.png
--------------------------------------------------------------------------------
/doc/courseLive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/courseLive.png
--------------------------------------------------------------------------------
/doc/demo_page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/demo_page.png
--------------------------------------------------------------------------------
/doc/en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/en.png
--------------------------------------------------------------------------------
/doc/seewoScan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/doc/seewoScan.png
--------------------------------------------------------------------------------
/glide/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/glide/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | kotlinOptions {
27 | jvmTarget = '1.8'
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation rootProject.ext.deps.kotlin.coroutines.core
33 | implementation rootProject.ext.deps.kotlin.coroutines.android
34 |
35 | implementation rootProject.ext.deps.android.appcompat
36 | implementation rootProject.ext.deps.android.material
37 |
38 | implementation rootProject.ext.deps.glide
39 |
40 | compileOnly project(':core')
41 |
42 | }
43 |
44 | try {
45 | // Jenkins 打包时会调用这里
46 | apply from: "${project.rootDir}/gradles/jitpack-push.gradle"
47 | apply from: "${project.rootDir}/gradles/jfrog-push.gradle"
48 | } catch(Exception ignored) {
49 | }
--------------------------------------------------------------------------------
/glide/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=brick-ui-glide
2 | POM_NAME=brick-ui-glide
3 | POM_DESCRIPTION=BrickUI
--------------------------------------------------------------------------------
/glide/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/glide/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/glide/src/main/java/com/seewo/brick/glide/exception/GlideBlurTransformation.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.glide.exception
2 |
3 | import android.content.Context
4 | import android.graphics.Bitmap
5 | import android.renderscript.Allocation
6 | import android.renderscript.Element
7 | import android.renderscript.RenderScript
8 | import android.renderscript.ScriptIntrinsicBlur
9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
10 | import com.bumptech.glide.load.resource.bitmap.CenterCrop
11 | import com.bumptech.glide.load.resource.bitmap.TransformationUtils
12 | import java.security.MessageDigest
13 | import kotlin.math.roundToInt
14 |
15 | private const val BITMAP_SCALE = 0.5f
16 |
17 | class GlideBlurTransformation(private val context: Context, private val radius: Float) :
18 | CenterCrop() {
19 | override fun transform(
20 | pool: BitmapPool,
21 | toTransform: Bitmap,
22 | outWidth: Int,
23 | outHeight: Int
24 | ): Bitmap {
25 | val bitmap = TransformationUtils.centerCrop(pool, toTransform, outWidth, outHeight)
26 | return bitmap.blur(context, radius)
27 | }
28 |
29 | override fun updateDiskCacheKey(messageDigest: MessageDigest) {}
30 | }
31 |
32 | /**
33 | * 模糊图片
34 | */
35 | private fun Bitmap.blur(context: Context?, blurRadius: Float): Bitmap {
36 | // 计算图片缩小后的长宽
37 | val width = (width * BITMAP_SCALE).roundToInt()
38 | val height = (height * BITMAP_SCALE).roundToInt()
39 |
40 | // 将缩小后的图片做为预渲染的图片
41 | val inputBitmap = Bitmap.createScaledBitmap(this, width, height, false)
42 | // 创建一张渲染后的输出图片
43 | val outputBitmap = Bitmap.createBitmap(inputBitmap)
44 |
45 | // 创建RenderScript内核对象
46 | val rs = RenderScript.create(context)
47 | // 创建一个模糊效果的RenderScript的工具对象
48 | val blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs))
49 |
50 | // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间
51 | // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去
52 | val tmpIn = Allocation.createFromBitmap(rs, inputBitmap)
53 | val tmpOut = Allocation.createFromBitmap(rs, outputBitmap)
54 |
55 | // 设置渲染的模糊程度, 25f是最大模糊度
56 | blurScript.setRadius(blurRadius)
57 | // 设置blurScript对象的输入内存
58 | blurScript.setInput(tmpIn)
59 | // 将输出数据保存到输出内存中
60 | blurScript.forEach(tmpOut)
61 |
62 | // 将数据填充到Allocation中
63 | tmpOut.copyTo(outputBitmap)
64 | return outputBitmap
65 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | android.enableJetifier=true
19 | # Kotlin code style for this project: "official" or "obsolete":
20 | kotlin.code.style=official
21 | # Enables namespacing of each library's R class so that its R class includes only the
22 | # resources declared in the library itself and none from the library's dependencies,
23 | # thereby reducing the size of the R class for that library
24 | android.nonTransitiveRClass=true
25 | android.injected.testOnly=false
26 |
27 | GITLAB_URL=https://github.com/robin8yeung/BrickUI
28 |
29 | POM_VERSION_NAME = 0.2.43
30 | POM_GROUP=com.seewo.ui
31 | POM_PACKAGING=aar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robin8yeung/BrickUI/7841a5d78a18cef04fd775c36df653c1c1fae8bd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Aug 18 10:58:31 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradles/jfrog-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'com.jfrog.artifactory'
3 |
4 | task androidJavadocs(type: Javadoc) {
5 | source = android.sourceSets.main.java.srcDirs
6 | classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
7 | }
8 |
9 | task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
10 | getArchiveClassifier().set('javadoc')
11 | from androidJavadocs.destinationDir
12 | }
13 |
14 | task androidSourcesJar(type: Jar) {
15 | getArchiveClassifier().set('sources')
16 | from android.sourceSets.main.java.srcDirs
17 | }
18 |
19 | artifactoryPublish.dependsOn('build')
20 |
21 | publishing {
22 | publications {
23 | aar(MavenPublication) {
24 | groupId POM_GROUP
25 | version POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
26 | artifactId POM_ARTIFACT_ID
27 | artifact "$buildDir/outputs/aar/${project.name}-release.aar"
28 | artifact androidSourcesJar
29 |
30 | pom.withXml {
31 | asNode().appendNode('description', POM_DESCRIPTION + ' Git commit:' + getGitSha())
32 | final depsNode = asNode().appendNode('dependencies')
33 |
34 | def compileDeps = configurations.api.getAllDependencies()
35 | compileDeps += configurations.compile.getAllDependencies()
36 |
37 | def runtimeDeps = configurations.implementation.getAllDependencies()
38 | runtimeDeps -= compileDeps
39 |
40 | compileDeps.each { dep -> addPomDependency(depsNode, dep, "compile") }
41 | runtimeDeps.each { dep -> addPomDependency(depsNode, dep, "runtime") }
42 | if (depsNode.children().size() == 0) {
43 | asNode().remove(depsNode)
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
50 | artifactory {
51 | contextUrl = "https://artifactory.gz.cvte.cn/artifactory"
52 | publish {
53 | repository {
54 | repoKey = Boolean.valueOf(System.getProperty("snapshot")) ? "SR_maven_snapshots_local" : "SR_maven_releases_local"
55 | username = System.getProperty("username")
56 | password = System.getProperty("password")
57 | }
58 | defaults {
59 | publications('aar')
60 | properties = ['gitlab_url': GITLAB_URL, 'vcs.revision': System.getProperty("vcs")]
61 | }
62 | }
63 | }
64 |
65 | artifacts {
66 | archives androidSourcesJar
67 | }
68 |
--------------------------------------------------------------------------------
/gradles/jitpack-push.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 |
3 | task sourceJar(type: Jar) {
4 | from android.sourceSets.main.java.srcDirs
5 | archiveClassifier = "sources"
6 | }
7 |
8 | afterEvaluate {
9 | publishing {
10 | publications {
11 | release(MavenPublication) {
12 | from components.release
13 | artifact sourceJar
14 | groupId = POM_GROUP
15 | artifactId = POM_ARTIFACT_ID
16 | version = POM_VERSION_NAME + (Boolean.valueOf(System.getProperty("snapshot")) ? "-SNAPSHOT" : "")
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/gradles/utils.gradle:
--------------------------------------------------------------------------------
1 | ext {
2 | // 计算当前分支的提交数量,若执行失败,则返回 1
3 | getGitCommitCount = { String gitPath ->
4 | def count = ('git -C ' + gitPath + ' rev-list --count HEAD').execute()
5 | count.waitFor()
6 | if (count.exitValue() != 0) {
7 | return '1'
8 | }
9 | return count.text.trim()
10 | }
11 | getGitSha = {
12 | def sha = 'git rev-parse --short HEAD'.execute()
13 | sha.waitFor()
14 | if (sha.exitValue() != 0) {
15 | return ''
16 | }
17 | return sha.text.trim()
18 | }
19 | addPomDependency = { Node dependenciesNode, Dependency dep, String scope ->
20 | if (dep.group == null || dep.version == null || dep.name == null || dep.name == "unspecified") {
21 | return
22 | }
23 | final dependencyNode = dependenciesNode.appendNode('dependency')
24 | dependencyNode.appendNode('groupId', dep.group)
25 | dependencyNode.appendNode('artifactId', dep.name)
26 | dependencyNode.appendNode('version', dep.version)
27 | dependencyNode.appendNode('scope', scope)
28 | if (!dep.transitive) {
29 | final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
30 | exclusionNode.appendNode('groupId', '*')
31 | exclusionNode.appendNode('artifactId', '*')
32 | } else if (!dep.properties.excludeRules.empty) {
33 | final exclusionNode = dependencyNode.appendNode('exclusions').appendNode('exclusion')
34 | dep.properties.excludeRules.each { ExcludeRule rule ->
35 | exclusionNode.appendNode('groupId', rule.group ?: '*')
36 | exclusionNode.appendNode('artifactId', rule.module ?: '*')
37 | }
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/live/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/live/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | kotlinOptions {
27 | jvmTarget = '1.8'
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation rootProject.ext.deps.kotlin.coroutines.core
33 | implementation rootProject.ext.deps.kotlin.coroutines.android
34 |
35 | implementation rootProject.ext.deps.android.appcompat
36 | implementation rootProject.ext.deps.android.material
37 |
38 | implementation rootProject.ext.deps.ktx.core
39 |
40 | compileOnly project(':core')
41 | compileOnly project(':smart-refresh')
42 | compileOnly project(':loop-pager')
43 | compileOnly project(':glide')
44 | compileOnly rootProject.ext.deps.glide
45 |
46 | def lifecycle_version = "2.5.1"
47 |
48 | // LiveData
49 | implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
50 | // Lifecycles only (without ViewModel or LiveData)
51 | implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
52 |
53 | implementation rootProject.ext.deps.smart_refresh_new.core
54 | implementation rootProject.ext.deps.smart_refresh_new.classics_header
55 | implementation rootProject.ext.deps.smart_refresh_new.classics_footer
56 | }
57 |
58 | try {
59 | // Jenkins 打包时会调用这里
60 | apply from: "${project.rootDir}/gradles/jitpack-push.gradle"
61 | apply from: "${project.rootDir}/gradles/jfrog-push.gradle"
62 | } catch(Exception ignored) {
63 | }
--------------------------------------------------------------------------------
/live/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=brick-ui-live
2 | POM_NAME=brick-ui-live
3 | POM_DESCRIPTION=BrickUI
--------------------------------------------------------------------------------
/live/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/live/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/ktx/LifecycleKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.content.Context
4 | import android.view.View
5 | import androidx.fragment.app.Fragment
6 | import androidx.lifecycle.LifecycleOwner
7 |
8 | fun Context.inMyLifecycle(block: LifecycleOwner.() -> Unit) {
9 | if (this is LifecycleOwner) {
10 | block()
11 | }
12 | }
13 |
14 | fun View.inMyLifecycle(block: LifecycleOwner.() -> Unit) {
15 | context.run {
16 | if (this is LifecycleOwner) {
17 | block()
18 | }
19 | }
20 | }
21 |
22 | fun Fragment.inMyLifecycle(block: LifecycleOwner.() -> Unit) {
23 | block()
24 | }
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/ktx/LiveBrickViewKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.content.Context
4 | import android.graphics.Color
5 | import android.graphics.drawable.Drawable
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import androidx.annotation.ColorInt
9 | import androidx.annotation.IdRes
10 | import androidx.lifecycle.LifecycleOwner
11 | import androidx.lifecycle.LiveData
12 | import com.seewo.brick.params.EdgeInsets
13 | import com.seewo.brick.params.Shadow
14 | import com.seewo.brick.view.ShadowLayout
15 |
16 |
17 | /**
18 | * 外阴影容器
19 | * 支持通过代码来实现外阴影
20 | *
21 | * 注意:Android P以下的机型将关闭硬件加速
22 | */
23 | fun Context.liveShadowBox(
24 | width: Int = WRAP_CONTENT,
25 | height: Int = WRAP_CONTENT,
26 | @IdRes id: Int? = null,
27 | tag: Any? = null,
28 | foreground: Drawable? = null,
29 | background: Drawable? = null,
30 | padding: EdgeInsets? = null,
31 | visibility: LiveData? = null,
32 | isSelected: LiveData? = null,
33 | onClick: View.OnClickListener? = null,
34 | lifecycleOwner: LifecycleOwner? = null,
35 |
36 | @ColorInt color: Int = Color.WHITE,
37 | radius: Int = 0,
38 | shadow: Shadow = Shadow(),
39 |
40 | block: (ViewGroup.() -> Unit)? = null
41 | ) = shadowBox(
42 | width, height, id, tag, foreground, background, padding,
43 | onClick = onClick,
44 | color = color, radius = radius, shadow = shadow, block = block
45 | ).apply {
46 | if (lifecycleOwner != null) {
47 | visibility?.bind(lifecycleOwner) {
48 | it ?: return@bind
49 | this@apply.visibility = it
50 | }
51 | isSelected?.bind(lifecycleOwner) {
52 | it ?: return@bind
53 | this@apply.isSelected = it
54 | }
55 | } else {
56 | visibility?.bind(context) {
57 | it ?: return@bind
58 | this@apply.visibility = it
59 | }
60 | isSelected?.bind(context) {
61 | it ?: return@bind
62 | this@apply.isSelected = it
63 | }
64 | }
65 | }
66 |
67 | /**
68 | * 外阴影容器
69 | * 支持通过代码来实现外阴影
70 | *
71 | * 注意:Android P以下的机型将关闭硬件加速
72 | */
73 | fun ViewGroup.liveShadowBox(
74 | width: Int = WRAP_CONTENT,
75 | height: Int = WRAP_CONTENT,
76 | @IdRes id: Int? = null,
77 | tag: Any? = null,
78 | foreground: Drawable? = null,
79 | background: Drawable? = null,
80 | margin: EdgeInsets? = null,
81 | padding: EdgeInsets? = null,
82 | visibility: LiveData? = null,
83 | isSelected: LiveData? = null,
84 | onClick: View.OnClickListener? = null,
85 | lifecycleOwner: LifecycleOwner? = null,
86 |
87 | @ColorInt color: Int = Color.WHITE,
88 | radius: Int = 0,
89 | shadow: Shadow = Shadow(),
90 |
91 | block: (ShadowLayout.() -> Unit)? = null
92 | ) = shadowBox(
93 | width, height, id, tag, foreground, background, margin, padding,
94 | onClick = onClick,
95 | color = color, radius = radius, shadow = shadow, block = block
96 | ).apply {
97 | if (lifecycleOwner != null) {
98 | visibility?.bind(lifecycleOwner) {
99 | it ?: return@bind
100 | this@apply.visibility = it
101 | }
102 | isSelected?.bind(lifecycleOwner) {
103 | it ?: return@bind
104 | this@apply.isSelected = it
105 | }
106 | } else {
107 | visibility?.bind(context) {
108 | it ?: return@bind
109 | this@apply.visibility = it
110 | }
111 | isSelected?.bind(context) {
112 | it ?: return@bind
113 | this@apply.isSelected = it
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/ktx/LiveDataKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.content.Context
4 | import android.os.Looper
5 | import android.view.View
6 | import androidx.lifecycle.LifecycleOwner
7 | import androidx.lifecycle.LiveData
8 | import androidx.lifecycle.MediatorLiveData
9 | import androidx.lifecycle.MutableLiveData
10 | import androidx.lifecycle.Transformations
11 | import com.seewo.brick.live.params.StaticData
12 |
13 | /**
14 | * set方法用于对于MutableLiveData类型的LiveData设置value,并保证不会因为线程问题抛异常
15 | * get方法用于取非空值,简化代码。需调用者保证value不为null,否则请用value属性
16 | */
17 | var LiveData.data: T
18 | set(value) {
19 | if (this is MutableLiveData) {
20 | if (Looper.myLooper() == Looper.getMainLooper()) {
21 | this.value = value
22 | } else {
23 | postValue(value)
24 | }
25 | }
26 | }
27 | get() = value!!
28 |
29 | /**
30 | * 对LiveData进行重新映射
31 | */
32 | fun LiveData.map(mapper: (I) -> O) =
33 | Transformations.map(this) {
34 | mapper(it)
35 | }
36 |
37 | /**
38 | * 过滤掉重复的数据
39 | */
40 | fun LiveData.distinctUntilChanged(): LiveData =
41 | Transformations.distinctUntilChanged(this)
42 |
43 | /**
44 | * 组合多个LiveData
45 | */
46 | fun LiveData.combine(liveData: LiveData, block: (I1?, I2?) -> O): LiveData =
47 | MediatorLiveData().apply {
48 | addSource(this@combine) { value = block(it, liveData.value) }
49 | addSource(liveData) { value = block(this@combine.value, it) }
50 | }
51 |
52 | /**
53 | * 把Boolean类型的LiveData取反,可以结合toVisibility使用。
54 | *
55 | * 举例:
56 | * val isGone = true.live
57 | * val visibility = isGone.inverse.toVisibility()
58 | */
59 | val LiveData.inverse: LiveData
60 | get() = map { !it }
61 |
62 | /**
63 | * LiveData的操作符重载,作用与LiveData.inverse相同
64 | *
65 | * 举例:
66 | * val isGone = true.live
67 | * val visibility = !isGone.toVisibility()
68 | */
69 | operator fun LiveData.not() = map { !it }
70 |
71 | /**
72 | * 把Boolean类型的LiveData映射成View的Visibility类型
73 | * true对应View.VISIBLE
74 | *
75 | * @param whenFalse 当LiveData的值为false时,View的Visibility状态。默认为GONE
76 | */
77 | fun LiveData.toVisibility(whenFalse: Int = View.GONE) = map { show ->
78 | View.VISIBLE.takeIf { show } ?: whenFalse
79 | }
80 |
81 | val T.live: MutableLiveData
82 | get() = MutableLiveData(this)
83 |
84 | val T?.static: LiveData
85 | get() = StaticData(this)
86 |
87 | fun LiveData.bind(lifecycleOwner: LifecycleOwner, binder: (T?) -> Unit) {
88 | if (this is StaticData) {
89 | binder(value)
90 | } else {
91 | distinctUntilChanged().observe(lifecycleOwner) {
92 | binder(it)
93 | }
94 | }
95 | }
96 |
97 | fun LiveData.bindNotNull(lifecycleOwner: LifecycleOwner, binder: (T) -> Unit) =
98 | bind(lifecycleOwner) {
99 | it ?: return@bind
100 | binder(it)
101 | }
102 |
103 | fun LiveData.bind(context: Context, binder: (T?) -> Unit) {
104 | context.inMyLifecycle {
105 | if (this@bind is StaticData) {
106 | binder(value)
107 | } else {
108 | distinctUntilChanged().observe(this) {
109 | binder(it)
110 | }
111 | }
112 | }
113 | }
114 |
115 | fun LiveData.bindNotNull(context: Context, binder: (T) -> Unit) =
116 | bind(context) {
117 | it ?: return@bind
118 | binder(it)
119 | }
120 |
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/ktx/LiveResourceKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.graphics.drawable.Drawable
4 | import androidx.lifecycle.LiveData
5 |
6 |
7 | val Int.DRAWABLE: LiveData
8 | get() = drawable.static
9 |
10 | val Int.COLOR: LiveData
11 | get() = color.static
12 |
13 | val Int.COLOR_DRAWABLE: LiveData
14 | get() = colorDrawable.static
15 |
16 | val Int.STRING: LiveData
17 | get() = string.static
18 |
19 | val Int.DIMENSION: LiveData
20 | get() = dimension.static
21 |
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/ktx/LiveSmartRefreshKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.Drawable
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.IdRes
8 | import androidx.lifecycle.LifecycleOwner
9 | import androidx.lifecycle.LiveData
10 | import com.scwang.smart.refresh.layout.api.RefreshFooter
11 | import com.scwang.smart.refresh.layout.api.RefreshHeader
12 | import com.scwang.smart.refresh.layout.api.RefreshLayout
13 | import com.seewo.brick.params.EdgeInsets
14 |
15 | /**
16 | * SmartRefresh的BrickUI封装
17 | *
18 | * 注意:使用时必须保证项目中引入了以下依赖:
19 | * implementation 'com.github.robin8yeung.BrickUI:brick-ui-smart-refresh:{VERSION}'
20 | */
21 | fun ViewGroup.liveSmartRefresh(
22 | width: Int = MATCH_PARENT, height: Int = MATCH_PARENT,
23 | @IdRes id: Int? = null,
24 | tag: Any? = null,
25 | foreground: Drawable? = null,
26 | background: Drawable? = null,
27 | margin: EdgeInsets? = null,
28 | padding: EdgeInsets? = null,
29 | visibility: LiveData? = null,
30 | lifecycleOwner: LifecycleOwner? = null,
31 |
32 | refreshEnable: LiveData? = null,
33 | loadMoreEnable: LiveData? = null,
34 | noMoreData: LiveData? = null,
35 | autoLoadMore: Boolean = true,
36 | onRefresh: ((RefreshLayout) -> Unit)? = null,
37 | onLoadMore: ((RefreshLayout) -> Unit)? = null,
38 | refreshHeader: RefreshHeader? = null,
39 | headerHeight: Int? = null,
40 | refreshFooter: RefreshFooter? = null,
41 | footerHeight: Int? = null,
42 | block: (Context.() -> View)? = null
43 | ) = smartRefresh(
44 | width, height, id, tag, foreground, background, margin, padding,
45 | autoLoadMore = autoLoadMore,
46 | onRefresh = onRefresh, onLoadMore = onLoadMore,
47 | refreshHeader = refreshHeader, headerHeight = headerHeight,
48 | refreshFooter = refreshFooter, footerHeight = footerHeight,
49 | block = block
50 | ).apply {
51 | if (lifecycleOwner != null) {
52 | refreshEnable?.bindNotNull(lifecycleOwner) {
53 | setEnableRefresh(it)
54 | }
55 | loadMoreEnable?.bindNotNull(lifecycleOwner) {
56 | setEnableLoadMore(it)
57 | }
58 | noMoreData?.bindNotNull(lifecycleOwner) {
59 | setNoMoreData(it)
60 | }
61 | visibility?.bindNotNull(lifecycleOwner) {
62 | this@apply.visibility = it
63 | }
64 | } else {
65 | refreshEnable?.bindNotNull(context) {
66 | setEnableRefresh(it)
67 | }
68 | loadMoreEnable?.bindNotNull(context) {
69 | setEnableLoadMore(it)
70 | }
71 | noMoreData?.bindNotNull(context) {
72 | setNoMoreData(it)
73 | }
74 | visibility?.bindNotNull(context) {
75 | this@apply.visibility = it
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/live/src/main/java/com/seewo/brick/live/params/StaticData.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.live.params
2 |
3 | import androidx.lifecycle.LiveData
4 |
5 | class StaticData(data: T?): LiveData(data)
--------------------------------------------------------------------------------
/loop-pager/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/loop-pager/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | kotlinOptions {
27 | jvmTarget = '1.8'
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation rootProject.ext.deps.kotlin.coroutines.core
33 | implementation rootProject.ext.deps.kotlin.coroutines.android
34 |
35 | implementation rootProject.ext.deps.android.appcompat
36 | implementation rootProject.ext.deps.android.material
37 |
38 | compileOnly project(':core')
39 |
40 | }
41 |
42 | try {
43 | // Jenkins 打包时会调用这里
44 | apply from: "${project.rootDir}/gradles/jitpack-push.gradle"
45 | apply from: "${project.rootDir}/gradles/jfrog-push.gradle"
46 | } catch(Exception ignored) {
47 | }
--------------------------------------------------------------------------------
/loop-pager/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=brick-ui-loop-pager
2 | POM_NAME=brick-ui-loop-pager
3 | POM_DESCRIPTION=BrickUI
--------------------------------------------------------------------------------
/loop-pager/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/loop-pager/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/loop-pager/src/main/java/com/seewo/brick/indicator/CircleIndicator.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.indicator
2 |
3 | import android.content.Context
4 | import android.database.DataSetObserver
5 | import androidx.viewpager.widget.ViewPager
6 | import androidx.viewpager.widget.ViewPager.OnPageChangeListener
7 |
8 | /**
9 | * CircleIndicator work with ViewPager
10 | */
11 | class CircleIndicator(context: Context) : BaseCircleIndicator(context) {
12 | private var mViewpager: ViewPager? = null
13 |
14 | fun setViewPager(viewPager: ViewPager) {
15 | viewPager.also {
16 | mViewpager = it
17 | }.apply {
18 | mLastPosition = -1
19 | createIndicators()
20 | removeOnPageChangeListener(mInternalPageChangeListener)
21 | addOnPageChangeListener(mInternalPageChangeListener)
22 | mInternalPageChangeListener.onPageSelected(currentItem)
23 | mViewpager?.adapter?.registerDataSetObserver(dataSetObserver)
24 | }
25 | }
26 |
27 | private fun createIndicators() {
28 | createIndicators(
29 | mViewpager?.adapter?.count ?: 0,
30 | mViewpager?.currentItem ?: 0,
31 | )
32 | }
33 |
34 | private val mInternalPageChangeListener: OnPageChangeListener = object : OnPageChangeListener {
35 | override fun onPageScrolled(
36 | position: Int, positionOffset: Float,
37 | positionOffsetPixels: Int
38 | ) = Unit
39 |
40 | override fun onPageSelected(position: Int) {
41 | if ((mViewpager?.adapter?.count ?: -1) <= 0) return
42 | animatePageSelected(position)
43 | }
44 |
45 | override fun onPageScrollStateChanged(state: Int) {}
46 | }
47 |
48 | val dataSetObserver: DataSetObserver = object : DataSetObserver() {
49 | override fun onChanged() {
50 | super.onChanged()
51 | val adapter = mViewpager?.adapter ?: return
52 | val newCount = adapter.count
53 | val currentCount = childCount
54 | mLastPosition = if (newCount == currentCount) {
55 | // No change
56 | return
57 | } else if (mLastPosition < newCount) {
58 | mViewpager!!.currentItem
59 | } else {
60 | -1
61 | }
62 | createIndicators()
63 | }
64 | }
65 |
66 | @Deprecated("User ViewPager addOnPageChangeListener")
67 | fun setOnPageChangeListener(
68 | onPageChangeListener: OnPageChangeListener?
69 | ) {
70 | if (mViewpager == null) {
71 | throw NullPointerException("can not find Viewpager , setViewPager first")
72 | }
73 | if (onPageChangeListener == null) {
74 | mViewpager!!.clearOnPageChangeListeners()
75 | } else {
76 | mViewpager!!.removeOnPageChangeListener(onPageChangeListener)
77 | mViewpager!!.addOnPageChangeListener(onPageChangeListener)
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/loop-pager/src/main/java/com/seewo/brick/indicator/CircleIndicator3.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.indicator
2 |
3 | import android.content.Context
4 | import androidx.recyclerview.widget.RecyclerView
5 | import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver
6 | import androidx.viewpager2.widget.ViewPager2
7 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
8 |
9 | /**
10 | * CircleIndicator work with ViewPager2
11 | */
12 | class CircleIndicator3(context: Context) : BaseCircleIndicator(context) {
13 | private var mViewpager: ViewPager2? = null
14 |
15 | fun setViewPager(viewPager: ViewPager2) {
16 | mViewpager = viewPager
17 | if (mViewpager?.adapter != null) {
18 | mLastPosition = -1
19 | createIndicators()
20 | mViewpager?.unregisterOnPageChangeCallback(mInternalPageChangeCallback)
21 | mViewpager?.registerOnPageChangeCallback(mInternalPageChangeCallback)
22 | mInternalPageChangeCallback.onPageSelected(mViewpager?.currentItem ?: 0)
23 | }
24 | }
25 |
26 | private fun createIndicators() {
27 | val count: Int = mViewpager?.adapter?.itemCount ?: 0
28 | createIndicators(count, mViewpager?.currentItem ?: 0)
29 | }
30 |
31 | private val mInternalPageChangeCallback: OnPageChangeCallback =
32 | object : OnPageChangeCallback() {
33 | override fun onPageSelected(position: Int) {
34 | val adapter = mViewpager?.adapter ?: return
35 | if (position == mLastPosition || adapter.itemCount <= 0) {
36 | return
37 | }
38 | animatePageSelected(position)
39 | }
40 | }
41 |
42 | val adapterDataObserver: AdapterDataObserver = object : AdapterDataObserver() {
43 | override fun onChanged() {
44 | super.onChanged()
45 | val adapter = mViewpager?.adapter ?: return
46 | val newCount = adapter.itemCount
47 | val currentCount = childCount
48 | mLastPosition = if (newCount == currentCount) {
49 | // No change
50 | return
51 | } else if (mLastPosition < newCount) {
52 | mViewpager!!.currentItem
53 | } else {
54 | RecyclerView.NO_POSITION
55 | }
56 | createIndicators()
57 | }
58 |
59 | override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
60 | super.onItemRangeChanged(positionStart, itemCount)
61 | onChanged()
62 | }
63 |
64 | override fun onItemRangeChanged(
65 | positionStart: Int, itemCount: Int,
66 | payload: Any?
67 | ) {
68 | super.onItemRangeChanged(positionStart, itemCount, payload)
69 | onChanged()
70 | }
71 |
72 | override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
73 | super.onItemRangeInserted(positionStart, itemCount)
74 | onChanged()
75 | }
76 |
77 | override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
78 | super.onItemRangeRemoved(positionStart, itemCount)
79 | onChanged()
80 | }
81 |
82 | override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {
83 | super.onItemRangeMoved(fromPosition, toPosition, itemCount)
84 | onChanged()
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/loop-pager/src/main/java/com/seewo/brick/ktx/InternalKTX.kt:
--------------------------------------------------------------------------------
1 | package com.seewo.brick.ktx
2 |
3 | import android.graphics.drawable.Drawable
4 | import android.os.Build
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import androidx.annotation.IdRes
8 | import com.seewo.brick.params.EdgeInsets
9 |
10 |
11 | internal fun View.setup(
12 | width: Int = WRAP_CONTENT,
13 | height: Int = WRAP_CONTENT,
14 | @IdRes id: Int? = null,
15 | tag: Any? = null,
16 | foreground: Drawable? = null,
17 | background: Drawable? = null,
18 | padding: EdgeInsets? = null,
19 | visibility: Int? = null,
20 | isSelected: Boolean? = null,
21 | isEnabled: Boolean? = null,
22 | onClick: View.OnClickListener? = null,
23 | fitsSystemWindows: Boolean? = null,
24 | ) {
25 | init(width, height)
26 | id?.let { this.id = it }
27 | tag?.let { this.tag = it }
28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
29 | foreground?.let {
30 | this.foreground = it
31 | }
32 | }
33 | background?.let { this.background = it }
34 | padding?.let { setPadding(it.start, it.top, it.end, it.bottom) }
35 | visibility?.let { this.visibility = it }
36 | isSelected?.let { this.isSelected = it }
37 | isEnabled?.let { this.isEnabled = it }
38 | onClick?.let { setOnClickListener(it) }
39 | fitsSystemWindows?.let { this.fitsSystemWindows = fitsSystemWindows }
40 | }
41 |
42 | internal fun T.applyMargin(
43 | margin: EdgeInsets? = null,
44 | ): T = apply {
45 | margin?.let {
46 | (layoutParams as? ViewGroup.MarginLayoutParams)?.setMargins(
47 | it.start, it.top, it.end, it.bottom
48 | )
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/loop-pager/src/main/res/animator/scale_with_alpha.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
16 |
17 |
22 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | maven { url 'https://maven.aliyun.com/repository/google' } // google()
4 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } // maven { url "https://plugins.gradle.org/m2/" }
5 | }
6 | }
7 | dependencyResolutionManagement {
8 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
9 | repositories {
10 | maven { url 'https://maven.aliyun.com/repository/public' } // jcenter()
11 | maven { url 'https://maven.aliyun.com/repository/google' } // google()
12 | maven { url 'https://maven.aliyun.com/repository/central' } // mavenCentral()
13 | }
14 | }
15 | rootProject.name = "BrickUI"
16 | include ':app'
17 | include ':core'
18 | include ':live'
19 | include ':glide'
20 | include ':smart-refresh'
21 | include ':loop-pager'
22 |
--------------------------------------------------------------------------------
/smart-refresh/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/smart-refresh/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 32
8 |
9 | defaultConfig {
10 | minSdk 21
11 | targetSdk 32
12 |
13 | consumerProguardFiles "consumer-rules.pro"
14 | }
15 |
16 | buildTypes {
17 | release {
18 | minifyEnabled false
19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20 | }
21 | }
22 | compileOptions {
23 | sourceCompatibility JavaVersion.VERSION_1_8
24 | targetCompatibility JavaVersion.VERSION_1_8
25 | }
26 | kotlinOptions {
27 | jvmTarget = '1.8'
28 | }
29 | }
30 |
31 | dependencies {
32 | implementation rootProject.ext.deps.kotlin.coroutines.core
33 | implementation rootProject.ext.deps.kotlin.coroutines.android
34 |
35 | implementation rootProject.ext.deps.android.appcompat
36 | implementation rootProject.ext.deps.android.material
37 |
38 | implementation rootProject.ext.deps.smart_refresh_new.core
39 | implementation rootProject.ext.deps.smart_refresh_new.classics_header
40 | implementation rootProject.ext.deps.smart_refresh_new.classics_footer
41 |
42 | compileOnly project(':core')
43 |
44 | }
45 |
46 | try {
47 | // Jenkins 打包时会调用这里
48 | apply from: "${project.rootDir}/gradles/jitpack-push.gradle"
49 | apply from: "${project.rootDir}/gradles/jfrog-push.gradle"
50 | } catch(Exception ignored) {
51 | }
--------------------------------------------------------------------------------
/smart-refresh/gradle.properties:
--------------------------------------------------------------------------------
1 | POM_ARTIFACT_ID=brick-ui-smart-refresh
2 | POM_NAME=brick-ui-smart-refresh
3 | POM_DESCRIPTION=BrickUI
--------------------------------------------------------------------------------
/smart-refresh/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/smart-refresh/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/versions.gradle:
--------------------------------------------------------------------------------
1 | ext.versions = [
2 | 'gradle': '4.1.3',
3 | 'matrix': '2.0.2',
4 | 'kotlin': [
5 | 'core': '1.7.10',
6 | 'coroutines': '1.6.1'
7 | ],
8 | 'test': [
9 | 'junit': '4.13.2',
10 | ],
11 | 'android': [
12 | 'appcompat': '1.4.1',
13 | 'material': '1.6.1',
14 | 'constraintlayout': '2.1.4',
15 | 'test': [
16 | 'junit': '1.1.3',
17 | 'espresso': [
18 | 'core': '3.4.0',
19 | ],
20 | ],
21 | 'flexbox': '3.0.0',
22 | ],
23 | 'jetpack': [
24 | 'startup': "1.1.1",
25 | 'lifecycle': '2.5.0',
26 | 'room': '2.2.5',
27 | ],
28 | 'sqlite_jdbc': '3.34.0', // for aarch64
29 | 'okhttp': '3.12.0',
30 | 'retrofit': '2.9.0',
31 | 'glide': '4.12.0',
32 | 'ijkplayer': '0.8.8',
33 | 'smart_refresh': '1.1.0-alpha-14',
34 | 'smart_refresh_new': '2.0.5',
35 | 'gson': '2.8.9',
36 | 'lottie': "2.7.0",
37 | 'xxpermissions': '6.0',
38 | 'walle': '1.1.6',
39 | 'bugly': [
40 | 'upgrade': '1.6.1',
41 | 'ndk': '3.9.2'
42 | ],
43 | 'tbs': '44199',
44 | 'wechat_sdk_without_mta': '5.4.3',
45 | 'discrete_scrollview': "1.4.9",
46 | 'geetest': '4.3.4.6',
47 | 'one_login': '2.7.5.1',
48 | 'scan_kit': '2.6.0.300',
49 | 'svga_player': "2.5.12",
50 | 'eventbus': '3.1.1',
51 | 'toast': "8.0",
52 | 'arouter': [
53 | 'core': '1.5.2',
54 | 'register': '1.0.2',
55 | 'compiler': '1.2.2',
56 | ],
57 | 'debug_db': '1.0.6',
58 | 'rxjava2': [
59 | 'rxjava': '2.2.6',
60 | 'rxandroid': '2.1.1',
61 | ],
62 | 'camerax': '1.2.0-alpha02',
63 | 'netty': '4.1.69.Final',
64 | 'ktx': [
65 | 'core': "1.7.0",
66 | 'collection': "1.2.0",
67 | 'fragment': "1.4.1",
68 | 'activity': "1.2.3",
69 | 'lifecycle': "2.5.1",
70 | ],
71 | 'lib': [
72 | 'utils': '2.0.69',
73 | 'common': '2.1.6',
74 | 'log': '1.0.12',
75 | 'screen_camera': '2.2.5',
76 | 'mirror': "0.1.2",
77 | 'signal': [
78 | 'sia': "0.1.2",
79 | ],
80 | 'venom': '1.0.7',
81 | 'friday': '1.2.16',
82 | 'ijkplayer': '0.8.8-b930dc3',
83 | 'audio': "1.0.11",
84 | 'js': "1.1.0",
85 | 'http_server': "1.0.1",
86 | 'imageset': "1.1.0",
87 | ],
88 |
89 | 'rtmq': [
90 | 'base': '1.0.20',
91 | 'push': '1.0.7',
92 | 'im': '1.0.12.d'
93 | ],
94 |
95 | 'en': [
96 | 'apm': [
97 | 'core': '2.1.14',
98 | 'seewo_tracer': '3.0.7',
99 | ],
100 | 'domain': [
101 | 'signal': '0.3.2'
102 | ],
103 |
104 |
105 | ]
106 | ]
107 |
--------------------------------------------------------------------------------