Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
W
Widget
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Android Widget
Widget
Commits
e39c45b3
Commit
e39c45b3
authored
Nov 06, 2019
by
王韦
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[new] 优化pop base
parent
99653783
Changes
32
Hide whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
2254 additions
and
42 deletions
+2254
-42
build.gradle
app/build.gradle
+2
-0
CommomPopActivity.kt
...c/main/java/com/qimai/android/widget/CommomPopActivity.kt
+43
-19
MainActivity.kt
app/src/main/java/com/qimai/android/widget/MainActivity.kt
+15
-1
TestWindow.kt
app/src/main/java/com/qimai/android/widget/TestWindow.kt
+36
-0
build.gradle
build.gradle
+1
-0
.gitignore
fragmentcontroller/.gitignore
+1
-0
build.gradle
fragmentcontroller/build.gradle
+41
-0
consumer-rules.pro
fragmentcontroller/consumer-rules.pro
+0
-0
complete_android_fragment_lifecycle.png
...entcontroller/img/complete_android_fragment_lifecycle.png
+0
-0
proguard-rules.pro
fragmentcontroller/proguard-rules.pro
+21
-0
ExampleInstrumentedTest.java
...i/android/fragmentcontroller/ExampleInstrumentedTest.java
+27
-0
AndroidManifest.xml
fragmentcontroller/src/main/AndroidManifest.xml
+2
-0
LifeFragment.kt
.../java/com/qmai/android/fragmentcontroller/LifeFragment.kt
+40
-0
strings.xml
fragmentcontroller/src/main/res/values/strings.xml
+3
-0
ExampleUnitTest.java
.../com/qmai/android/fragmentcontroller/ExampleUnitTest.java
+17
-0
settings.gradle
settings.gradle
+1
-1
build.gradle
tools/build.gradle
+1
-1
TimeFormat.kt
tools/src/main/java/com/qimai/android/tools/TimeFormat.kt
+34
-0
Pop.MD
widgetlib/Pop.MD
+25
-0
build.gradle
widgetlib/build.gradle
+3
-1
SpanUtils.java
...etlib/src/main/java/com/qimai/android/span/SpanUtils.java
+1414
-0
SectionItemView.java
...ain/java/com/qimai/android/widgetlib/SectionItemView.java
+60
-0
AbsQMBasePopup.kt
.../java/com/qimai/android/widgetlib/popup/AbsQMBasePopup.kt
+172
-0
CommonPopWindow.kt
...java/com/qimai/android/widgetlib/popup/CommonPopWindow.kt
+21
-7
Loading.kt
...rc/main/java/com/qimai/android/widgetlib/popup/Loading.kt
+39
-0
QMBasePopup.kt
...ain/java/com/qimai/android/widgetlib/popup/QMBasePopup.kt
+1
-1
QmAlertDialog.kt
...n/java/com/qimai/android/widgetlib/popup/QmAlertDialog.kt
+27
-11
HolderContext.java
...java/com/qimai/android/widgetlib/toast/HolderContext.java
+38
-0
ToastUtils.java
...in/java/com/qimai/android/widgetlib/toast/ToastUtils.java
+125
-0
loading.xml
widgetlib/src/main/res/layout/loading.xml
+29
-0
section_itemview.xml
widgetlib/src/main/res/layout/section_itemview.xml
+7
-0
attrs.xml
widgetlib/src/main/res/values/attrs.xml
+8
-0
No files found.
app/build.gradle
View file @
e39c45b3
...
...
@@ -35,4 +35,6 @@ dependencies {
// implementation 'com.qmai.android.sdk:widgetlib:1.1.2-SNAPSHOT'
implementation
project
(
path:
':tools'
)
implementation
'androidx.recyclerview:recyclerview:1.0.0'
}
app/src/main/java/com/qimai/android/widget/CommomPopActivity.kt
View file @
e39c45b3
...
...
@@ -4,10 +4,13 @@ import android.os.Bundle
import
android.widget.Button
import
android.widget.Toast
import
androidx.appcompat.app.AppCompatActivity
import
com.qimai.android.tools.V
import
com.qimai.android.widgetlib.popup.CommonPopWindow
import
com.qimai.android.widgetlib.popup.QmAlertDialog
class
CommomPopActivity
:
AppCompatActivity
()
{
var
dialog
:
QmAlertDialog
?
=
null
var
i
=
0L
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_commom_pop
)
...
...
@@ -26,30 +29,51 @@ class CommomPopActivity : AppCompatActivity() {
// .build()
// commonPopWindow.show(findViewById(R.id.root))
// commonPopWindow.dimBehind(0.5f)
//
QmAlertDialog
.
Builder
()
.
withContext
(
this
)
.
withLeftButton
(
leftButtonText
=
"取消"
,
clickListener
=
{
Toast
.
makeText
(
this
,
"取消"
,
Toast
.
LENGTH_SHORT
).
show
()
it
.
dismiss
()
})
.
withRightButton
(
rightButtonText
=
"确定"
,
clickListener
=
{
i
=
System
.
currentTimeMillis
()
"$i"
.
V
()
// i.hashCode().toString().V()
if
(
dialog
==
null
)
{
val
right
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
=
{
Toast
.
makeText
(
this
,
"确定"
,
Toast
.
LENGTH_SHORT
).
show
()
it
.
dismiss
()
"$i"
.
V
()
// "---------${i.hashCode()}".V()
}
dialog
=
QmAlertDialog
.
Builder
()
.
withContext
(
this
)
.
withLeftButton
(
leftButtonText
=
"取消"
,
clickListener
=
{
Toast
.
makeText
(
this
,
"取消"
,
Toast
.
LENGTH_SHORT
).
show
()
it
.
dismiss
()
})
.
withRightButton
(
rightButtonText
=
"确定"
,
clickListener
=
right
).
withRootView
(
findViewById
(
R
.
id
.
root
)
)
.
withTitle
(
"订单1111"
)
.
withSubTitle
(
"子标题"
)
.
withWidth
(
400
)
.
build
()
}
dialog
?.
show
()
}).
withRootView
(
findViewById
(
R
.
id
.
root
)
)
.
withTitle
(
"订单1111"
)
.
withSubTitle
(
"子标题"
)
.
build
()
.
show
()
}
}
fun
test
(
b
:
Int
):
()
->
Int
{
var
a
=
3
return
fun
():
Int
{
a
++
return
a
+
b
}
}
}
app/src/main/java/com/qimai/android/widget/MainActivity.kt
View file @
e39c45b3
...
...
@@ -4,15 +4,29 @@ import android.content.Intent
import
android.os.Bundle
import
android.widget.Button
import
androidx.appcompat.app.AppCompatActivity
import
com.qimai.android.widgetlib.toast.HolderContext
class
MainActivity
:
AppCompatActivity
()
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_main
)
HolderContext
.
getInstance
().
register
{
MainActivity
@
this
}
findViewById
<
Button
>(
R
.
id
.
commonPop
).
setOnClickListener
{
startActivity
(
Intent
(
MainActivity
@
this
,
CommomPopActivity
::
class
.
java
))
// ToastUtils.getInstance().showCenter("测试测试")
// ToastUtils.getInstance().setMsgColor(Color.RED).showTaost("测试出的的")
//
//// startActivity(Intent(MainActivity@ this, CommomPopActivity::class.java))
//// val loding = Loading()
//// loding.isCancelable =false
//// loding.show(supportFragmentManager, "loading")
TestWindow
(
this
,
findViewById
<
Button
>(
R
.
id
.
commonPop
)).
build
().
show
()
}
findViewById
<
Button
>(
R
.
id
.
tip
).
setOnClickListener
{
...
...
app/src/main/java/com/qimai/android/widget/TestWindow.kt
0 → 100644
View file @
e39c45b3
package
com.qimai.android.widget
import
android.content.Context
import
android.graphics.Point
import
android.view.Gravity
import
android.view.LayoutInflater
import
android.view.View
import
com.qimai.android.tools.dpTopx
import
com.qimai.android.tools.getScreenWidth
import
com.qimai.android.widgetlib.popup.AbsQMBasePopup
/**
* created by wangwei ON 2019-11-06 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
class
TestWindow
constructor
(
var
ctx
:
Context
,
var
anchor
:
View
)
:
AbsQMBasePopup
(
ctx
)
{
override
fun
onShowEnd
()
{
dimBehind
(
0.5f
)
}
override
fun
config
():
WindowConfig
{
return
AbsQMBasePopup
.
WindowConfig
().
apply
{
mContentView
=
LayoutInflater
.
from
(
ctx
).
inflate
(
R
.
layout
.
qm_alert_content
,
null
)
mAnchorView
=
anchor
mWindowWidth
=
getScreenWidth
(
ctx
)
-
ctx
.
dpTopx
(
30.0f
)
mGravity
=
Gravity
.
CENTER
}
}
override
fun
onShowBegin
(
contentView
:
View
):
Point
{
return
Point
(
0
,
0
)
}
}
\ No newline at end of file
build.gradle
View file @
e39c45b3
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript
{
ext
.
kotlin_version
=
'1.3.50'
ext
.
kotlin_version
=
'1.3.41'
repositories
{
maven
{
url
'http://maven.aliyun.com/nexus/content/groups/public/'
}
// 阿里云镜像
...
...
fragmentcontroller/.gitignore
0 → 100644
View file @
e39c45b3
/build
fragmentcontroller/build.gradle
0 → 100644
View file @
e39c45b3
apply
plugin:
'com.android.library'
apply
plugin:
'kotlin-android-extensions'
apply
plugin:
'kotlin-android'
android
{
compileSdkVersion
29
buildToolsVersion
"29.0.2"
defaultConfig
{
minSdkVersion
19
targetSdkVersion
29
versionCode
1
versionName
"1.0"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles
'consumer-rules.pro'
}
buildTypes
{
release
{
minifyEnabled
false
proguardFiles
getDefaultProguardFile
(
'proguard-android-optimize.txt'
),
'proguard-rules.pro'
}
}
}
dependencies
{
implementation
fileTree
(
dir:
'libs'
,
include:
[
'*.jar'
])
implementation
'androidx.appcompat:appcompat:1.1.0'
testImplementation
'junit:junit:4.12'
androidTestImplementation
'androidx.test.ext:junit:1.1.0'
androidTestImplementation
'androidx.test.espresso:espresso-core:3.2.0'
compile
"androidx.core:core-ktx:+"
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
repositories
{
mavenCentral
()
}
fragmentcontroller/consumer-rules.pro
0 → 100644
View file @
e39c45b3
fragmentcontroller/img/complete_android_fragment_lifecycle.png
0 → 100644
View file @
e39c45b3
390 KB
fragmentcontroller/proguard-rules.pro
0 → 100644
View file @
e39c45b3
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
fragmentcontroller/src/androidTest/java/com/qmai/android/fragmentcontroller/ExampleInstrumentedTest.java
0 → 100644
View file @
e39c45b3
package
com
.
qmai
.
android
.
fragmentcontroller
;
import
android.content.Context
;
import
androidx.test.platform.app.InstrumentationRegistry
;
import
androidx.test.ext.junit.runners.AndroidJUnit4
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
static
org
.
junit
.
Assert
.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith
(
AndroidJUnit4
.
class
)
public
class
ExampleInstrumentedTest
{
@Test
public
void
useAppContext
()
{
// Context of the app under test.
Context
appContext
=
InstrumentationRegistry
.
getInstrumentation
().
getTargetContext
();
assertEquals
(
"com.qmai.android.fragmentcontroller.test"
,
appContext
.
getPackageName
());
}
}
fragmentcontroller/src/main/AndroidManifest.xml
0 → 100644
View file @
e39c45b3
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"com.qmai.android.fragmentcontroller"
/>
fragmentcontroller/src/main/java/com/qmai/android/fragmentcontroller/LifeFragment.kt
0 → 100644
View file @
e39c45b3
package
com.qmai.android.fragmentcontroller
import
android.content.Context
import
android.os.Bundle
import
android.util.AttributeSet
import
android.view.View
import
androidx.fragment.app.Fragment
/**
* created by wangwei ON 2019-10-29 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
class
LifeFragment
:
Fragment
(){
override
fun
onAttach
(
context
:
Context
)
{
super
.
onAttach
(
context
)
}
override
fun
onDestroy
()
{
super
.
onDestroy
()
}
override
fun
onInflate
(
context
:
Context
,
attrs
:
AttributeSet
,
savedInstanceState
:
Bundle
?)
{
super
.
onInflate
(
context
,
attrs
,
savedInstanceState
)
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
}
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
super
.
onViewCreated
(
view
,
savedInstanceState
)
}
override
fun
onActivityCreated
(
savedInstanceState
:
Bundle
?)
{
super
.
onActivityCreated
(
savedInstanceState
)
}
}
\ No newline at end of file
fragmentcontroller/src/main/res/values/strings.xml
0 → 100644
View file @
e39c45b3
<resources>
<string
name=
"app_name"
>
FragmentController
</string>
</resources>
fragmentcontroller/src/test/java/com/qmai/android/fragmentcontroller/ExampleUnitTest.java
0 → 100644
View file @
e39c45b3
package
com
.
qmai
.
android
.
fragmentcontroller
;
import
org.junit.Test
;
import
static
org
.
junit
.
Assert
.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public
class
ExampleUnitTest
{
@Test
public
void
addition_isCorrect
()
{
assertEquals
(
4
,
2
+
2
);
}
}
\ No newline at end of file
settings.gradle
View file @
e39c45b3
include
':app'
,
':widgetlib'
,
':tools'
include
':app'
,
':widgetlib'
,
':tools'
,
':fragmentcontroller'
tools/build.gradle
View file @
e39c45b3
...
...
@@ -42,7 +42,7 @@ repositories {
group
'com.qmai.android.tools'
version
'1.1.
6
-SNAPSHOT'
version
'1.1.
7
-SNAPSHOT'
gradlePublish
{
...
...
tools/src/main/java/com/qimai/android/tools/TimeFormat.kt
0 → 100644
View file @
e39c45b3
package
com.qimai.android.tools
import
java.text.SimpleDateFormat
import
java.util.*
/**
* created by wangwei ON 2019-09-23 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
fun
formatCurrentDate
(
pattern
:
String
)
=
getTimeFormatStr
(
pattern
)
private
fun
getTimeFormatStr
(
pattern
:
String
,
original
:
Any
=
Date
())
=
SimpleDateFormat
(
pattern
,
Locale
.
getDefault
()).
format
(
original
)
?:
""
/**获取当前年份**/
val
currentYear
:
Int
get
()
=
Calendar
.
getInstance
().
get
(
Calendar
.
YEAR
)
/**获取当前月份**/
val
currentMonth
get
()
=
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
)
+
1
/**获取当前日**/
val
currentDay
:
Int
get
()
=
Calendar
.
getInstance
().
get
(
Calendar
.
DATE
)
/**获取当前时间戳**/
val
currentTimeMillis
:
Long
get
()
=
System
.
currentTimeMillis
()
widgetlib/Pop.MD
0 → 100644
View file @
e39c45b3
````
class TestWindow constructor(var ctx: Context, var anchor: View) : AbsQMBasePopup(ctx) {
override fun onShowEnd() {
dimBehind(0.5f)
}
override fun config(): WindowConfig {
return AbsQMBasePopup.WindowConfig().apply {
mContentView = LayoutInflater.from(ctx).inflate(R.layout.qm_alert_content, null)
mAnchorView = anchor
mWindowWidth = getScreenWidth(ctx) - ctx.dpTopx(30.0f)
mGravity = Gravity.CENTER
}
}
override fun onShowBegin(contentView: View): Point {
return Point(0, 0)
}
}
````
` 显示 TestWindow(this, anchorView).build().show()
`
\ No newline at end of file
widgetlib/build.gradle
View file @
e39c45b3
...
...
@@ -37,6 +37,8 @@ dependencies {
implementation
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation
project
(
path:
':tools'
)
implementation
'androidx.recyclerview:recyclerview:1.0.0'
implementation
'com.github.ybq:Android-SpinKit:1.4.0'
// implementation 'com.qmai.android.tools:tools:1.1.1-SNAPSHOT'
}
repositories
{
...
...
@@ -45,7 +47,7 @@ repositories {
group
'com.qmai.android.sdk'
version
'1.1.1
2
-SNAPSHOT'
version
'1.1.1
8
-SNAPSHOT'
gradlePublish
{
...
...
widgetlib/src/main/java/com/qimai/android/span/SpanUtils.java
0 → 100644
View file @
e39c45b3
package
com
.
qimai
.
android
.
span
;
import
android.annotation.SuppressLint
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.graphics.BlurMaskFilter
;
import
android.graphics.Canvas
;
import
android.graphics.Color
;
import
android.graphics.Paint
;
import
android.graphics.Path
;
import
android.graphics.Rect
;
import
android.graphics.Shader
;
import
android.graphics.Typeface
;
import
android.graphics.drawable.BitmapDrawable
;
import
android.graphics.drawable.Drawable
;
import
android.net.Uri
;
import
android.text.Layout
;
import
android.text.SpannableStringBuilder
;
import
android.text.Spanned
;
import
android.text.TextPaint
;
import
android.text.method.LinkMovementMethod
;
import
android.text.style.AbsoluteSizeSpan
;
import
android.text.style.AlignmentSpan
;
import
android.text.style.BackgroundColorSpan
;
import
android.text.style.CharacterStyle
;
import
android.text.style.ClickableSpan
;
import
android.text.style.ForegroundColorSpan
;
import
android.text.style.LeadingMarginSpan
;
import
android.text.style.LineHeightSpan
;
import
android.text.style.MaskFilterSpan
;
import
android.text.style.RelativeSizeSpan
;
import
android.text.style.ReplacementSpan
;
import
android.text.style.ScaleXSpan
;
import
android.text.style.StrikethroughSpan
;
import
android.text.style.StyleSpan
;
import
android.text.style.SubscriptSpan
;
import
android.text.style.SuperscriptSpan
;
import
android.text.style.TypefaceSpan
;
import
android.text.style.URLSpan
;
import
android.text.style.UnderlineSpan
;
import
android.text.style.UpdateAppearance
;
import
android.util.Log
;
import
android.widget.TextView
;
import
androidx.annotation.ColorInt
;
import
androidx.annotation.DrawableRes
;
import
androidx.annotation.FloatRange
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.IntRange
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
androidx.core.content.ContextCompat
;
import
com.qimai.android.widgetlib.toast.HolderContext
;
import
java.io.InputStream
;
import
java.io.Serializable
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.ref.WeakReference
;
/**
* created by wangwei ON 2019-11-04 email:wangwei_5521@163.com
*
* @version 1.1.1
* @Description
**/
public
class
SpanUtils
{
private
static
final
int
COLOR_DEFAULT
=
0xFEFFFFFF
;
public
static
final
int
ALIGN_BOTTOM
=
0
;
public
static
final
int
ALIGN_BASELINE
=
1
;
public
static
final
int
ALIGN_CENTER
=
2
;
public
static
final
int
ALIGN_TOP
=
3
;
@IntDef
({
ALIGN_BOTTOM
,
ALIGN_BASELINE
,
ALIGN_CENTER
,
ALIGN_TOP
})
@Retention
(
RetentionPolicy
.
SOURCE
)
public
@interface
Align
{
}
private
static
final
String
LINE_SEPARATOR
=
System
.
getProperty
(
"line.separator"
);
private
TextView
mTextView
;
private
CharSequence
mText
;
private
int
flag
;
private
int
foregroundColor
;
private
int
backgroundColor
;
private
int
lineHeight
;
private
int
alignLine
;
private
int
quoteColor
;
private
int
stripeWidth
;
private
int
quoteGapWidth
;
private
int
first
;
private
int
rest
;
private
int
bulletColor
;
private
int
bulletRadius
;
private
int
bulletGapWidth
;
private
int
fontSize
;
private
boolean
fontSizeIsDp
;
private
float
proportion
;
private
float
xProportion
;
private
boolean
isStrikethrough
;
private
boolean
isUnderline
;
private
boolean
isSuperscript
;
private
boolean
isSubscript
;
private
boolean
isBold
;
private
boolean
isItalic
;
private
boolean
isBoldItalic
;
private
String
fontFamily
;
private
Typeface
typeface
;
private
Layout
.
Alignment
alignment
;
private
int
verticalAlign
;
private
ClickableSpan
clickSpan
;
private
String
url
;
private
float
blurRadius
;
private
BlurMaskFilter
.
Blur
style
;
private
Shader
shader
;
private
float
shadowRadius
;
private
float
shadowDx
;
private
float
shadowDy
;
private
int
shadowColor
;
private
Object
[]
spans
;
private
Bitmap
imageBitmap
;
private
Drawable
imageDrawable
;
private
Uri
imageUri
;
private
int
imageResourceId
;
private
int
alignImage
;
private
int
spaceSize
;
private
int
spaceColor
;
private
SerializableSpannableStringBuilder
mBuilder
;
private
int
mType
;
private
final
int
mTypeCharSequence
=
0
;
private
final
int
mTypeImage
=
1
;
private
final
int
mTypeSpace
=
2
;
private
SpanUtils
(
TextView
textView
)
{
this
();
mTextView
=
textView
;
}
public
SpanUtils
()
{
mBuilder
=
new
SerializableSpannableStringBuilder
();
mText
=
""
;
mType
=
-
1
;
setDefault
();
}
private
void
setDefault
()
{
flag
=
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
;
foregroundColor
=
COLOR_DEFAULT
;
backgroundColor
=
COLOR_DEFAULT
;
lineHeight
=
-
1
;
quoteColor
=
COLOR_DEFAULT
;
first
=
-
1
;
bulletColor
=
COLOR_DEFAULT
;
fontSize
=
-
1
;
proportion
=
-
1
;
xProportion
=
-
1
;
isStrikethrough
=
false
;
isUnderline
=
false
;
isSuperscript
=
false
;
isSubscript
=
false
;
isBold
=
false
;
isItalic
=
false
;
isBoldItalic
=
false
;
fontFamily
=
null
;
typeface
=
null
;
alignment
=
null
;
verticalAlign
=
-
1
;
clickSpan
=
null
;
url
=
null
;
blurRadius
=
-
1
;
shader
=
null
;
shadowRadius
=
-
1
;
spans
=
null
;
imageBitmap
=
null
;
imageDrawable
=
null
;
imageUri
=
null
;
imageResourceId
=
-
1
;
spaceSize
=
-
1
;
}
/**
* Set the span of flag.
*
* @param flag The flag.
* <ul>
* <li>{@link Spanned#SPAN_INCLUSIVE_EXCLUSIVE}</li>
* <li>{@link Spanned#SPAN_INCLUSIVE_INCLUSIVE}</li>
* <li>{@link Spanned#SPAN_EXCLUSIVE_EXCLUSIVE}</li>
* <li>{@link Spanned#SPAN_EXCLUSIVE_INCLUSIVE}</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFlag
(
final
int
flag
)
{
this
.
flag
=
flag
;
return
this
;
}
/**
* Set the span of foreground's color.
*
* @param color The color of foreground
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setForegroundColor
(
@ColorInt
final
int
color
)
{
this
.
foregroundColor
=
color
;
return
this
;
}
/**
* Set the span of background's color.
*
* @param color The color of background
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBackgroundColor
(
@ColorInt
final
int
color
)
{
this
.
backgroundColor
=
color
;
return
this
;
}
/**
* Set the span of line height.
*
* @param lineHeight The line height, in pixel.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setLineHeight
(
@IntRange
(
from
=
0
)
final
int
lineHeight
)
{
return
setLineHeight
(
lineHeight
,
ALIGN_CENTER
);
}
/**
* Set the span of line height.
*
* @param lineHeight The line height, in pixel.
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER}</li>
* <li>{@link Align#ALIGN_BOTTOM}</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setLineHeight
(
@IntRange
(
from
=
0
)
final
int
lineHeight
,
@Align
final
int
align
)
{
this
.
lineHeight
=
lineHeight
;
this
.
alignLine
=
align
;
return
this
;
}
/**
* Set the span of quote's color.
*
* @param color The color of quote
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setQuoteColor
(
@ColorInt
final
int
color
)
{
return
setQuoteColor
(
color
,
2
,
2
);
}
/**
* Set the span of quote's color.
*
* @param color The color of quote.
* @param stripeWidth The width of stripe, in pixel.
* @param gapWidth The width of gap, in pixel.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setQuoteColor
(
@ColorInt
final
int
color
,
@IntRange
(
from
=
1
)
final
int
stripeWidth
,
@IntRange
(
from
=
0
)
final
int
gapWidth
)
{
this
.
quoteColor
=
color
;
this
.
stripeWidth
=
stripeWidth
;
this
.
quoteGapWidth
=
gapWidth
;
return
this
;
}
/**
* Set the span of leading margin.
*
* @param first The indent for the first line of the paragraph.
* @param rest The indent for the remaining lines of the paragraph.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setLeadingMargin
(
@IntRange
(
from
=
0
)
final
int
first
,
@IntRange
(
from
=
0
)
final
int
rest
)
{
this
.
first
=
first
;
this
.
rest
=
rest
;
return
this
;
}
/**
* Set the span of bullet.
*
* @param gapWidth The width of gap, in pixel.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBullet
(
@IntRange
(
from
=
0
)
final
int
gapWidth
)
{
return
setBullet
(
0
,
3
,
gapWidth
);
}
/**
* Set the span of bullet.
*
* @param color The color of bullet.
* @param radius The radius of bullet, in pixel.
* @param gapWidth The width of gap, in pixel.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBullet
(
@ColorInt
final
int
color
,
@IntRange
(
from
=
0
)
final
int
radius
,
@IntRange
(
from
=
0
)
final
int
gapWidth
)
{
this
.
bulletColor
=
color
;
this
.
bulletRadius
=
radius
;
this
.
bulletGapWidth
=
gapWidth
;
return
this
;
}
/**
* Set the span of font's size.
*
* @param size The size of font.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFontSize
(
@IntRange
(
from
=
0
)
final
int
size
)
{
return
setFontSize
(
size
,
false
);
}
/**
* Set the span of size of font.
*
* @param size The size of font.
* @param isSp True to use sp, false to use pixel.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFontSize
(
@IntRange
(
from
=
0
)
final
int
size
,
final
boolean
isSp
)
{
this
.
fontSize
=
size
;
this
.
fontSizeIsDp
=
isSp
;
return
this
;
}
/**
* Set the span of proportion of font.
*
* @param proportion The proportion of font.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFontProportion
(
final
float
proportion
)
{
this
.
proportion
=
proportion
;
return
this
;
}
/**
* Set the span of transverse proportion of font.
*
* @param proportion The transverse proportion of font.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFontXProportion
(
final
float
proportion
)
{
this
.
xProportion
=
proportion
;
return
this
;
}
/**
* Set the span of strikethrough.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setStrikethrough
()
{
this
.
isStrikethrough
=
true
;
return
this
;
}
/**
* Set the span of underline.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setUnderline
()
{
this
.
isUnderline
=
true
;
return
this
;
}
/**
* Set the span of superscript.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setSuperscript
()
{
this
.
isSuperscript
=
true
;
return
this
;
}
/**
* Set the span of subscript.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setSubscript
()
{
this
.
isSubscript
=
true
;
return
this
;
}
/**
* Set the span of bold.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBold
()
{
isBold
=
true
;
return
this
;
}
/**
* Set the span of italic.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setItalic
()
{
isItalic
=
true
;
return
this
;
}
/**
* Set the span of bold italic.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBoldItalic
()
{
isBoldItalic
=
true
;
return
this
;
}
/**
* Set the span of font family.
*
* @param fontFamily The font family.
* <ul>
* <li>monospace</li>
* <li>serif</li>
* <li>sans-serif</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setFontFamily
(
@NonNull
final
String
fontFamily
)
{
this
.
fontFamily
=
fontFamily
;
return
this
;
}
/**
* Set the span of typeface.
*
* @param typeface The typeface.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setTypeface
(
@NonNull
final
Typeface
typeface
)
{
this
.
typeface
=
typeface
;
return
this
;
}
/**
* Set the span of horizontal alignment.
*
* @param alignment The alignment.
* <ul>
* <li>{@link android.text.Layout.Alignment#ALIGN_NORMAL }</li>
* <li>{@link android.text.Layout.Alignment#ALIGN_OPPOSITE}</li>
* <li>{@link android.text.Layout.Alignment#ALIGN_CENTER }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setHorizontalAlign
(
@NonNull
final
Layout
.
Alignment
alignment
)
{
this
.
alignment
=
alignment
;
return
this
;
}
/**
* Set the span of vertical alignment.
*
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER }</li>
* <li>{@link Align#ALIGN_BASELINE}</li>
* <li>{@link Align#ALIGN_BOTTOM }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setVerticalAlign
(
@Align
final
int
align
)
{
this
.
verticalAlign
=
align
;
return
this
;
}
/**
* Set the span of click.
* <p>Must set {@code view.setMovementMethod(LinkMovementMethod.getInstance())}</p>
*
* @param clickSpan The span of click.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setClickSpan
(
@NonNull
final
ClickableSpan
clickSpan
)
{
if
(
mTextView
!=
null
&&
mTextView
.
getMovementMethod
()
==
null
)
{
mTextView
.
setMovementMethod
(
LinkMovementMethod
.
getInstance
());
}
this
.
clickSpan
=
clickSpan
;
return
this
;
}
/**
* Set the span of url.
* <p>Must set {@code view.setMovementMethod(LinkMovementMethod.getInstance())}</p>
*
* @param url The url.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setUrl
(
@NonNull
final
String
url
)
{
if
(
mTextView
!=
null
&&
mTextView
.
getMovementMethod
()
==
null
)
{
mTextView
.
setMovementMethod
(
LinkMovementMethod
.
getInstance
());
}
this
.
url
=
url
;
return
this
;
}
/**
* Set the span of blur.
*
* @param radius The radius of blur.
* @param style The style.
* <ul>
* <li>{@link android.graphics.BlurMaskFilter.Blur#NORMAL}</li>
* <li>{@link android.graphics.BlurMaskFilter.Blur#SOLID}</li>
* <li>{@link android.graphics.BlurMaskFilter.Blur#OUTER}</li>
* <li>{@link android.graphics.BlurMaskFilter.Blur#INNER}</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setBlur
(
@FloatRange
(
from
=
0
,
fromInclusive
=
false
)
final
float
radius
,
final
android
.
graphics
.
BlurMaskFilter
.
Blur
style
)
{
this
.
blurRadius
=
radius
;
this
.
style
=
style
;
return
this
;
}
/**
* Set the span of shader.
*
* @param shader The shader.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setShader
(
@NonNull
final
Shader
shader
)
{
this
.
shader
=
shader
;
return
this
;
}
/**
* Set the span of shadow.
*
* @param radius The radius of shadow.
* @param dx X-axis offset, in pixel.
* @param dy Y-axis offset, in pixel.
* @param shadowColor The color of shadow.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setShadow
(
@FloatRange
(
from
=
0
,
fromInclusive
=
false
)
final
float
radius
,
final
float
dx
,
final
float
dy
,
final
int
shadowColor
)
{
this
.
shadowRadius
=
radius
;
this
.
shadowDx
=
dx
;
this
.
shadowDy
=
dy
;
this
.
shadowColor
=
shadowColor
;
return
this
;
}
/**
* Set the spans.
*
* @param spans The spans.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
setSpans
(
@NonNull
final
Object
...
spans
)
{
if
(
spans
.
length
>
0
)
{
this
.
spans
=
spans
;
}
return
this
;
}
/**
* Append the text text.
*
* @param text The text.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
append
(
@NonNull
final
CharSequence
text
)
{
apply
(
mTypeCharSequence
);
mText
=
text
;
return
this
;
}
/**
* Append one line.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendLine
()
{
apply
(
mTypeCharSequence
);
mText
=
LINE_SEPARATOR
;
return
this
;
}
/**
* Append text and one line.
*
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendLine
(
@NonNull
final
CharSequence
text
)
{
apply
(
mTypeCharSequence
);
mText
=
text
+
LINE_SEPARATOR
;
return
this
;
}
/**
* Append one image.
*
* @param bitmap The bitmap of image.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Bitmap
bitmap
)
{
return
appendImage
(
bitmap
,
ALIGN_BOTTOM
);
}
/**
* Append one image.
*
* @param bitmap The bitmap.
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER }</li>
* <li>{@link Align#ALIGN_BASELINE}</li>
* <li>{@link Align#ALIGN_BOTTOM }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Bitmap
bitmap
,
@Align
final
int
align
)
{
apply
(
mTypeImage
);
this
.
imageBitmap
=
bitmap
;
this
.
alignImage
=
align
;
return
this
;
}
/**
* Append one image.
*
* @param drawable The drawable of image.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Drawable
drawable
)
{
return
appendImage
(
drawable
,
ALIGN_BOTTOM
);
}
/**
* Append one image.
*
* @param drawable The drawable of image.
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER }</li>
* <li>{@link Align#ALIGN_BASELINE}</li>
* <li>{@link Align#ALIGN_BOTTOM }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Drawable
drawable
,
@Align
final
int
align
)
{
apply
(
mTypeImage
);
this
.
imageDrawable
=
drawable
;
this
.
alignImage
=
align
;
return
this
;
}
/**
* Append one image.
*
* @param uri The uri of image.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Uri
uri
)
{
return
appendImage
(
uri
,
ALIGN_BOTTOM
);
}
/**
* Append one image.
*
* @param uri The uri of image.
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER }</li>
* <li>{@link Align#ALIGN_BASELINE}</li>
* <li>{@link Align#ALIGN_BOTTOM }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@NonNull
final
Uri
uri
,
@Align
final
int
align
)
{
apply
(
mTypeImage
);
this
.
imageUri
=
uri
;
this
.
alignImage
=
align
;
return
this
;
}
/**
* Append one image.
*
* @param resourceId The resource id of image.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@DrawableRes
final
int
resourceId
)
{
return
appendImage
(
resourceId
,
ALIGN_BOTTOM
);
}
/**
* Append one image.
*
* @param resourceId The resource id of image.
* @param align The alignment.
* <ul>
* <li>{@link Align#ALIGN_TOP }</li>
* <li>{@link Align#ALIGN_CENTER }</li>
* <li>{@link Align#ALIGN_BASELINE}</li>
* <li>{@link Align#ALIGN_BOTTOM }</li>
* </ul>
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendImage
(
@DrawableRes
final
int
resourceId
,
@Align
final
int
align
)
{
apply
(
mTypeImage
);
this
.
imageResourceId
=
resourceId
;
this
.
alignImage
=
align
;
return
this
;
}
/**
* Append space.
*
* @param size The size of space.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendSpace
(
@IntRange
(
from
=
0
)
final
int
size
)
{
return
appendSpace
(
size
,
Color
.
TRANSPARENT
);
}
/**
* Append space.
*
* @param size The size of space.
* @param color The color of space.
* @return the single {@link SpanUtils} instance
*/
public
SpanUtils
appendSpace
(
@IntRange
(
from
=
0
)
final
int
size
,
@ColorInt
final
int
color
)
{
apply
(
mTypeSpace
);
spaceSize
=
size
;
spaceColor
=
color
;
return
this
;
}
private
void
apply
(
final
int
type
)
{
applyLast
();
mType
=
type
;
}
public
SpannableStringBuilder
get
()
{
return
mBuilder
;
}
/**
* Create the span string.
*
* @return the span string
*/
public
SpannableStringBuilder
create
()
{
applyLast
();
if
(
mTextView
!=
null
)
{
mTextView
.
setText
(
mBuilder
);
}
return
mBuilder
;
}
private
void
applyLast
()
{
if
(
mType
==
mTypeCharSequence
)
{
updateCharCharSequence
();
}
else
if
(
mType
==
mTypeImage
)
{
updateImage
();
}
else
if
(
mType
==
mTypeSpace
)
{
updateSpace
();
}
setDefault
();
}
private
void
updateCharCharSequence
()
{
if
(
mText
.
length
()
==
0
)
return
;
int
start
=
mBuilder
.
length
();
if
(
start
==
0
&&
lineHeight
!=
-
1
)
{
// bug of LineHeightSpan when first line
mBuilder
.
append
(
Character
.
toString
((
char
)
2
))
.
append
(
"\n"
)
.
setSpan
(
new
AbsoluteSizeSpan
(
0
),
0
,
2
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
);
start
=
2
;
}
mBuilder
.
append
(
mText
);
int
end
=
mBuilder
.
length
();
if
(
verticalAlign
!=
-
1
)
{
mBuilder
.
setSpan
(
new
VerticalAlignSpan
(
verticalAlign
),
start
,
end
,
flag
);
}
if
(
foregroundColor
!=
COLOR_DEFAULT
)
{
mBuilder
.
setSpan
(
new
ForegroundColorSpan
(
foregroundColor
),
start
,
end
,
flag
);
}
if
(
backgroundColor
!=
COLOR_DEFAULT
)
{
mBuilder
.
setSpan
(
new
BackgroundColorSpan
(
backgroundColor
),
start
,
end
,
flag
);
}
if
(
first
!=
-
1
)
{
mBuilder
.
setSpan
(
new
LeadingMarginSpan
.
Standard
(
first
,
rest
),
start
,
end
,
flag
);
}
if
(
quoteColor
!=
COLOR_DEFAULT
)
{
mBuilder
.
setSpan
(
new
CustomQuoteSpan
(
quoteColor
,
stripeWidth
,
quoteGapWidth
),
start
,
end
,
flag
);
}
if
(
bulletColor
!=
COLOR_DEFAULT
)
{
mBuilder
.
setSpan
(
new
CustomBulletSpan
(
bulletColor
,
bulletRadius
,
bulletGapWidth
),
start
,
end
,
flag
);
}
if
(
fontSize
!=
-
1
)
{
mBuilder
.
setSpan
(
new
AbsoluteSizeSpan
(
fontSize
,
fontSizeIsDp
),
start
,
end
,
flag
);
}
if
(
proportion
!=
-
1
)
{
mBuilder
.
setSpan
(
new
RelativeSizeSpan
(
proportion
),
start
,
end
,
flag
);
}
if
(
xProportion
!=
-
1
)
{
mBuilder
.
setSpan
(
new
ScaleXSpan
(
xProportion
),
start
,
end
,
flag
);
}
if
(
lineHeight
!=
-
1
)
{
mBuilder
.
setSpan
(
new
CustomLineHeightSpan
(
lineHeight
,
alignLine
),
start
,
end
,
flag
);
}
if
(
isStrikethrough
)
{
mBuilder
.
setSpan
(
new
StrikethroughSpan
(),
start
,
end
,
flag
);
}
if
(
isUnderline
)
{
mBuilder
.
setSpan
(
new
UnderlineSpan
(),
start
,
end
,
flag
);
}
if
(
isSuperscript
)
{
mBuilder
.
setSpan
(
new
SuperscriptSpan
(),
start
,
end
,
flag
);
}
if
(
isSubscript
)
{
mBuilder
.
setSpan
(
new
SubscriptSpan
(),
start
,
end
,
flag
);
}
if
(
isBold
)
{
mBuilder
.
setSpan
(
new
StyleSpan
(
Typeface
.
BOLD
),
start
,
end
,
flag
);
}
if
(
isItalic
)
{
mBuilder
.
setSpan
(
new
StyleSpan
(
Typeface
.
ITALIC
),
start
,
end
,
flag
);
}
if
(
isBoldItalic
)
{
mBuilder
.
setSpan
(
new
StyleSpan
(
Typeface
.
BOLD_ITALIC
),
start
,
end
,
flag
);
}
if
(
fontFamily
!=
null
)
{
mBuilder
.
setSpan
(
new
TypefaceSpan
(
fontFamily
),
start
,
end
,
flag
);
}
if
(
typeface
!=
null
)
{
mBuilder
.
setSpan
(
new
CustomTypefaceSpan
(
typeface
),
start
,
end
,
flag
);
}
if
(
alignment
!=
null
)
{
mBuilder
.
setSpan
(
new
AlignmentSpan
.
Standard
(
alignment
),
start
,
end
,
flag
);
}
if
(
clickSpan
!=
null
)
{
mBuilder
.
setSpan
(
clickSpan
,
start
,
end
,
flag
);
}
if
(
url
!=
null
)
{
mBuilder
.
setSpan
(
new
URLSpan
(
url
),
start
,
end
,
flag
);
}
if
(
blurRadius
!=
-
1
)
{
mBuilder
.
setSpan
(
new
MaskFilterSpan
(
new
BlurMaskFilter
(
blurRadius
,
style
)),
start
,
end
,
flag
);
}
if
(
shader
!=
null
)
{
mBuilder
.
setSpan
(
new
ShaderSpan
(
shader
),
start
,
end
,
flag
);
}
if
(
shadowRadius
!=
-
1
)
{
mBuilder
.
setSpan
(
new
ShadowSpan
(
shadowRadius
,
shadowDx
,
shadowDy
,
shadowColor
),
start
,
end
,
flag
);
}
if
(
spans
!=
null
)
{
for
(
Object
span
:
spans
)
{
mBuilder
.
setSpan
(
span
,
start
,
end
,
flag
);
}
}
}
private
void
updateImage
()
{
int
start
=
mBuilder
.
length
();
mText
=
"<img>"
;
updateCharCharSequence
();
int
end
=
mBuilder
.
length
();
if
(
imageBitmap
!=
null
)
{
mBuilder
.
setSpan
(
new
CustomImageSpan
(
imageBitmap
,
alignImage
),
start
,
end
,
flag
);
}
else
if
(
imageDrawable
!=
null
)
{
mBuilder
.
setSpan
(
new
CustomImageSpan
(
imageDrawable
,
alignImage
),
start
,
end
,
flag
);
}
else
if
(
imageUri
!=
null
)
{
mBuilder
.
setSpan
(
new
CustomImageSpan
(
imageUri
,
alignImage
),
start
,
end
,
flag
);
}
else
if
(
imageResourceId
!=
-
1
)
{
mBuilder
.
setSpan
(
new
CustomImageSpan
(
imageResourceId
,
alignImage
),
start
,
end
,
flag
);
}
}
private
void
updateSpace
()
{
int
start
=
mBuilder
.
length
();
mText
=
"< >"
;
updateCharCharSequence
();
int
end
=
mBuilder
.
length
();
mBuilder
.
setSpan
(
new
SpaceSpan
(
spaceSize
,
spaceColor
),
start
,
end
,
flag
);
}
static
class
VerticalAlignSpan
extends
ReplacementSpan
{
static
final
int
ALIGN_CENTER
=
2
;
static
final
int
ALIGN_TOP
=
3
;
final
int
mVerticalAlignment
;
VerticalAlignSpan
(
int
verticalAlignment
)
{
mVerticalAlignment
=
verticalAlignment
;
}
@Override
public
int
getSize
(
@NonNull
Paint
paint
,
CharSequence
text
,
int
start
,
int
end
,
@Nullable
Paint
.
FontMetricsInt
fm
)
{
text
=
text
.
subSequence
(
start
,
end
);
return
(
int
)
paint
.
measureText
(
text
.
toString
());
}
@Override
public
void
draw
(
@NonNull
Canvas
canvas
,
CharSequence
text
,
int
start
,
int
end
,
float
x
,
int
top
,
int
y
,
int
bottom
,
@NonNull
Paint
paint
)
{
text
=
text
.
subSequence
(
start
,
end
);
Paint
.
FontMetricsInt
fm
=
paint
.
getFontMetricsInt
();
// int need = height - (v + fm.descent - fm.ascent - spanstartv);
// if (need > 0) {
// if (mVerticalAlignment == ALIGN_TOP) {
// fm.descent += need;
// } else if (mVerticalAlignment == ALIGN_CENTER) {
// fm.descent += need / 2;
// fm.ascent -= need / 2;
// } else {
// fm.ascent -= need;
// }
// }
// need = height - (v + fm.bottom - fm.top - spanstartv);
// if (need > 0) {
// if (mVerticalAlignment == ALIGN_TOP) {
// fm.bottom += need;
// } else if (mVerticalAlignment == ALIGN_CENTER) {
// fm.bottom += need / 2;
// fm.top -= need / 2;
// } else {
// fm.top -= need;
// }
// }
canvas
.
drawText
(
text
.
toString
(),
x
,
y
-
((
y
+
fm
.
descent
+
y
+
fm
.
ascent
)
/
2
-
(
bottom
+
top
)
/
2
),
paint
);
}
}
static
class
CustomLineHeightSpan
implements
LineHeightSpan
{
private
final
int
height
;
static
final
int
ALIGN_CENTER
=
2
;
static
final
int
ALIGN_TOP
=
3
;
final
int
mVerticalAlignment
;
static
Paint
.
FontMetricsInt
sfm
;
CustomLineHeightSpan
(
int
height
,
int
verticalAlignment
)
{
this
.
height
=
height
;
mVerticalAlignment
=
verticalAlignment
;
}
@Override
public
void
chooseHeight
(
final
CharSequence
text
,
final
int
start
,
final
int
end
,
final
int
spanstartv
,
final
int
v
,
final
Paint
.
FontMetricsInt
fm
)
{
if
(
sfm
==
null
)
{
sfm
=
new
Paint
.
FontMetricsInt
();
sfm
.
top
=
fm
.
top
;
sfm
.
ascent
=
fm
.
ascent
;
sfm
.
descent
=
fm
.
descent
;
sfm
.
bottom
=
fm
.
bottom
;
sfm
.
leading
=
fm
.
leading
;
}
else
{
fm
.
top
=
sfm
.
top
;
fm
.
ascent
=
sfm
.
ascent
;
fm
.
descent
=
sfm
.
descent
;
fm
.
bottom
=
sfm
.
bottom
;
fm
.
leading
=
sfm
.
leading
;
}
int
need
=
height
-
(
v
+
fm
.
descent
-
fm
.
ascent
-
spanstartv
);
if
(
need
>
0
)
{
if
(
mVerticalAlignment
==
ALIGN_TOP
)
{
fm
.
descent
+=
need
;
}
else
if
(
mVerticalAlignment
==
ALIGN_CENTER
)
{
fm
.
descent
+=
need
/
2
;
fm
.
ascent
-=
need
/
2
;
}
else
{
fm
.
ascent
-=
need
;
}
}
need
=
height
-
(
v
+
fm
.
bottom
-
fm
.
top
-
spanstartv
);
if
(
need
>
0
)
{
if
(
mVerticalAlignment
==
ALIGN_TOP
)
{
fm
.
bottom
+=
need
;
}
else
if
(
mVerticalAlignment
==
ALIGN_CENTER
)
{
fm
.
bottom
+=
need
/
2
;
fm
.
top
-=
need
/
2
;
}
else
{
fm
.
top
-=
need
;
}
}
if
(
end
==
((
Spanned
)
text
).
getSpanEnd
(
this
))
{
sfm
=
null
;
}
}
}
static
class
SpaceSpan
extends
ReplacementSpan
{
private
final
int
width
;
private
final
Paint
paint
=
new
Paint
();
private
SpaceSpan
(
final
int
width
)
{
this
(
width
,
Color
.
TRANSPARENT
);
}
private
SpaceSpan
(
final
int
width
,
final
int
color
)
{
super
();
this
.
width
=
width
;
paint
.
setColor
(
color
);
paint
.
setStyle
(
Paint
.
Style
.
FILL
);
}
@Override
public
int
getSize
(
@NonNull
final
Paint
paint
,
final
CharSequence
text
,
@IntRange
(
from
=
0
)
final
int
start
,
@IntRange
(
from
=
0
)
final
int
end
,
@Nullable
final
Paint
.
FontMetricsInt
fm
)
{
return
width
;
}
@Override
public
void
draw
(
@NonNull
final
Canvas
canvas
,
final
CharSequence
text
,
@IntRange
(
from
=
0
)
final
int
start
,
@IntRange
(
from
=
0
)
final
int
end
,
final
float
x
,
final
int
top
,
final
int
y
,
final
int
bottom
,
@NonNull
final
Paint
paint
)
{
canvas
.
drawRect
(
x
,
top
,
x
+
width
,
bottom
,
this
.
paint
);
}
}
static
class
CustomQuoteSpan
implements
LeadingMarginSpan
{
private
final
int
color
;
private
final
int
stripeWidth
;
private
final
int
gapWidth
;
private
CustomQuoteSpan
(
final
int
color
,
final
int
stripeWidth
,
final
int
gapWidth
)
{
super
();
this
.
color
=
color
;
this
.
stripeWidth
=
stripeWidth
;
this
.
gapWidth
=
gapWidth
;
}
public
int
getLeadingMargin
(
final
boolean
first
)
{
return
stripeWidth
+
gapWidth
;
}
public
void
drawLeadingMargin
(
final
Canvas
c
,
final
Paint
p
,
final
int
x
,
final
int
dir
,
final
int
top
,
final
int
baseline
,
final
int
bottom
,
final
CharSequence
text
,
final
int
start
,
final
int
end
,
final
boolean
first
,
final
Layout
layout
)
{
Paint
.
Style
style
=
p
.
getStyle
();
int
color
=
p
.
getColor
();
p
.
setStyle
(
Paint
.
Style
.
FILL
);
p
.
setColor
(
this
.
color
);
c
.
drawRect
(
x
,
top
,
x
+
dir
*
stripeWidth
,
bottom
,
p
);
p
.
setStyle
(
style
);
p
.
setColor
(
color
);
}
}
static
class
CustomBulletSpan
implements
LeadingMarginSpan
{
private
final
int
color
;
private
final
int
radius
;
private
final
int
gapWidth
;
private
Path
sBulletPath
=
null
;
private
CustomBulletSpan
(
final
int
color
,
final
int
radius
,
final
int
gapWidth
)
{
this
.
color
=
color
;
this
.
radius
=
radius
;
this
.
gapWidth
=
gapWidth
;
}
public
int
getLeadingMargin
(
final
boolean
first
)
{
return
2
*
radius
+
gapWidth
;
}
public
void
drawLeadingMargin
(
final
Canvas
c
,
final
Paint
p
,
final
int
x
,
final
int
dir
,
final
int
top
,
final
int
baseline
,
final
int
bottom
,
final
CharSequence
text
,
final
int
start
,
final
int
end
,
final
boolean
first
,
final
Layout
l
)
{
if
(((
Spanned
)
text
).
getSpanStart
(
this
)
==
start
)
{
Paint
.
Style
style
=
p
.
getStyle
();
int
oldColor
=
0
;
oldColor
=
p
.
getColor
();
p
.
setColor
(
color
);
p
.
setStyle
(
Paint
.
Style
.
FILL
);
if
(
c
.
isHardwareAccelerated
())
{
if
(
sBulletPath
==
null
)
{
sBulletPath
=
new
Path
();
// Bullet is slightly better to avoid aliasing artifacts on mdpi devices.
sBulletPath
.
addCircle
(
0.0f
,
0.0f
,
radius
,
Path
.
Direction
.
CW
);
}
c
.
save
();
c
.
translate
(
x
+
dir
*
radius
,
(
top
+
bottom
)
/
2.0f
);
c
.
drawPath
(
sBulletPath
,
p
);
c
.
restore
();
}
else
{
c
.
drawCircle
(
x
+
dir
*
radius
,
(
top
+
bottom
)
/
2.0f
,
radius
,
p
);
}
p
.
setColor
(
oldColor
);
p
.
setStyle
(
style
);
}
}
}
@SuppressLint
(
"ParcelCreator"
)
static
class
CustomTypefaceSpan
extends
TypefaceSpan
{
private
final
Typeface
newType
;
private
CustomTypefaceSpan
(
final
Typeface
type
)
{
super
(
""
);
newType
=
type
;
}
@Override
public
void
updateDrawState
(
final
TextPaint
textPaint
)
{
apply
(
textPaint
,
newType
);
}
@Override
public
void
updateMeasureState
(
final
TextPaint
paint
)
{
apply
(
paint
,
newType
);
}
private
void
apply
(
final
Paint
paint
,
final
Typeface
tf
)
{
int
oldStyle
;
Typeface
old
=
paint
.
getTypeface
();
if
(
old
==
null
)
{
oldStyle
=
0
;
}
else
{
oldStyle
=
old
.
getStyle
();
}
int
fake
=
oldStyle
&
~
tf
.
getStyle
();
if
((
fake
&
Typeface
.
BOLD
)
!=
0
)
{
paint
.
setFakeBoldText
(
true
);
}
if
((
fake
&
Typeface
.
ITALIC
)
!=
0
)
{
paint
.
setTextSkewX
(-
0.25f
);
}
paint
.
getShader
();
paint
.
setTypeface
(
tf
);
}
}
static
class
CustomImageSpan
extends
CustomDynamicDrawableSpan
{
private
Drawable
mDrawable
;
private
Uri
mContentUri
;
private
int
mResourceId
;
private
CustomImageSpan
(
final
Bitmap
b
,
final
int
verticalAlignment
)
{
super
(
verticalAlignment
);
mDrawable
=
new
BitmapDrawable
(
HolderContext
.
getContext
().
getResources
(),
b
);
mDrawable
.
setBounds
(
0
,
0
,
mDrawable
.
getIntrinsicWidth
(),
mDrawable
.
getIntrinsicHeight
()
);
}
private
CustomImageSpan
(
final
Drawable
d
,
final
int
verticalAlignment
)
{
super
(
verticalAlignment
);
mDrawable
=
d
;
mDrawable
.
setBounds
(
0
,
0
,
mDrawable
.
getIntrinsicWidth
(),
mDrawable
.
getIntrinsicHeight
()
);
}
private
CustomImageSpan
(
final
Uri
uri
,
final
int
verticalAlignment
)
{
super
(
verticalAlignment
);
mContentUri
=
uri
;
}
private
CustomImageSpan
(
@DrawableRes
final
int
resourceId
,
final
int
verticalAlignment
)
{
super
(
verticalAlignment
);
mResourceId
=
resourceId
;
}
@Override
public
Drawable
getDrawable
()
{
Drawable
drawable
=
null
;
if
(
mDrawable
!=
null
)
{
drawable
=
mDrawable
;
}
else
if
(
mContentUri
!=
null
)
{
Bitmap
bitmap
;
try
{
InputStream
is
=
HolderContext
.
getContext
().
getContentResolver
().
openInputStream
(
mContentUri
);
bitmap
=
BitmapFactory
.
decodeStream
(
is
);
drawable
=
new
BitmapDrawable
(
HolderContext
.
getContext
().
getResources
(),
bitmap
);
drawable
.
setBounds
(
0
,
0
,
drawable
.
getIntrinsicWidth
(),
drawable
.
getIntrinsicHeight
()
);
if
(
is
!=
null
)
{
is
.
close
();
}
}
catch
(
Exception
e
)
{
Log
.
e
(
"sms"
,
"Failed to loaded content "
+
mContentUri
,
e
);
}
}
else
{
try
{
drawable
=
ContextCompat
.
getDrawable
(
HolderContext
.
getContext
(),
mResourceId
);
drawable
.
setBounds
(
0
,
0
,
drawable
.
getIntrinsicWidth
(),
drawable
.
getIntrinsicHeight
()
);
}
catch
(
Exception
e
)
{
Log
.
e
(
"sms"
,
"Unable to find resource: "
+
mResourceId
);
}
}
return
drawable
;
}
}
static
abstract
class
CustomDynamicDrawableSpan
extends
ReplacementSpan
{
static
final
int
ALIGN_BOTTOM
=
0
;
static
final
int
ALIGN_BASELINE
=
1
;
static
final
int
ALIGN_CENTER
=
2
;
static
final
int
ALIGN_TOP
=
3
;
final
int
mVerticalAlignment
;
private
CustomDynamicDrawableSpan
()
{
mVerticalAlignment
=
ALIGN_BOTTOM
;
}
private
CustomDynamicDrawableSpan
(
final
int
verticalAlignment
)
{
mVerticalAlignment
=
verticalAlignment
;
}
public
abstract
Drawable
getDrawable
();
@Override
public
int
getSize
(
@NonNull
final
Paint
paint
,
final
CharSequence
text
,
final
int
start
,
final
int
end
,
final
Paint
.
FontMetricsInt
fm
)
{
Drawable
d
=
getCachedDrawable
();
Rect
rect
=
d
.
getBounds
();
if
(
fm
!=
null
)
{
int
lineHeight
=
fm
.
bottom
-
fm
.
top
;
if
(
lineHeight
<
rect
.
height
())
{
if
(
mVerticalAlignment
==
ALIGN_TOP
)
{
fm
.
top
=
fm
.
top
;
fm
.
bottom
=
rect
.
height
()
+
fm
.
top
;
}
else
if
(
mVerticalAlignment
==
ALIGN_CENTER
)
{
fm
.
top
=
-
rect
.
height
()
/
2
-
lineHeight
/
4
;
fm
.
bottom
=
rect
.
height
()
/
2
-
lineHeight
/
4
;
}
else
{
fm
.
top
=
-
rect
.
height
()
+
fm
.
bottom
;
fm
.
bottom
=
fm
.
bottom
;
}
fm
.
ascent
=
fm
.
top
;
fm
.
descent
=
fm
.
bottom
;
}
}
return
rect
.
right
;
}
@Override
public
void
draw
(
@NonNull
final
Canvas
canvas
,
final
CharSequence
text
,
final
int
start
,
final
int
end
,
final
float
x
,
final
int
top
,
final
int
y
,
final
int
bottom
,
@NonNull
final
Paint
paint
)
{
Drawable
d
=
getCachedDrawable
();
Rect
rect
=
d
.
getBounds
();
canvas
.
save
();
float
transY
;
int
lineHeight
=
bottom
-
top
;
if
(
rect
.
height
()
<
lineHeight
)
{
if
(
mVerticalAlignment
==
ALIGN_TOP
)
{
transY
=
top
;
}
else
if
(
mVerticalAlignment
==
ALIGN_CENTER
)
{
transY
=
(
bottom
+
top
-
rect
.
height
())
/
2
;
}
else
if
(
mVerticalAlignment
==
ALIGN_BASELINE
)
{
transY
=
y
-
rect
.
height
();
}
else
{
transY
=
bottom
-
rect
.
height
();
}
canvas
.
translate
(
x
,
transY
);
}
else
{
canvas
.
translate
(
x
,
top
);
}
d
.
draw
(
canvas
);
canvas
.
restore
();
}
private
Drawable
getCachedDrawable
()
{
WeakReference
<
Drawable
>
wr
=
mDrawableRef
;
Drawable
d
=
null
;
if
(
wr
!=
null
)
{
d
=
wr
.
get
();
}
if
(
d
==
null
)
{
d
=
getDrawable
();
mDrawableRef
=
new
WeakReference
<>(
d
);
}
return
d
;
}
private
WeakReference
<
Drawable
>
mDrawableRef
;
}
static
class
ShaderSpan
extends
CharacterStyle
implements
UpdateAppearance
{
private
Shader
mShader
;
private
ShaderSpan
(
final
Shader
shader
)
{
this
.
mShader
=
shader
;
}
@Override
public
void
updateDrawState
(
final
TextPaint
tp
)
{
tp
.
setShader
(
mShader
);
}
}
static
class
ShadowSpan
extends
CharacterStyle
implements
UpdateAppearance
{
private
float
radius
;
private
float
dx
,
dy
;
private
int
shadowColor
;
private
ShadowSpan
(
final
float
radius
,
final
float
dx
,
final
float
dy
,
final
int
shadowColor
)
{
this
.
radius
=
radius
;
this
.
dx
=
dx
;
this
.
dy
=
dy
;
this
.
shadowColor
=
shadowColor
;
}
@Override
public
void
updateDrawState
(
final
TextPaint
tp
)
{
tp
.
setShadowLayer
(
radius
,
dx
,
dy
,
shadowColor
);
}
}
private
static
class
SerializableSpannableStringBuilder
extends
SpannableStringBuilder
implements
Serializable
{
private
static
final
long
serialVersionUID
=
4909567650765875771L
;
}
///////////////////////////////////////////////////////////////////////////
// static
///////////////////////////////////////////////////////////////////////////
public
static
SpanUtils
with
(
final
TextView
textView
)
{
return
new
SpanUtils
(
textView
);
}
}
widgetlib/src/main/java/com/qimai/android/widgetlib/SectionItemView.java
0 → 100644
View file @
e39c45b3
package
com
.
qimai
.
android
.
widgetlib
;
import
android.content.Context
;
import
android.content.res.TypedArray
;
import
android.util.AttributeSet
;
import
android.widget.RelativeLayout
;
/**
* created by wangwei ON 2019-11-04 email:wangwei_5521@163.com
*
* @version 1.1.1
* @Description
**/
public
class
SectionItemView
extends
RelativeLayout
{
public
static
final
int
TYPE_ARROW
=
0
;
public
static
final
int
TYPE_CHECK
=
1
;
public
static
final
int
TYPE_RADIO
=
2
;
public
SectionItemView
(
Context
context
)
{
this
(
context
,
null
);
}
public
SectionItemView
(
Context
context
,
AttributeSet
attrs
)
{
this
(
context
,
attrs
,
0
);
}
public
SectionItemView
(
Context
context
,
AttributeSet
attrs
,
int
defStyleAttr
)
{
super
(
context
,
attrs
,
defStyleAttr
);
TypedArray
a
=
context
.
getTheme
().
obtainStyledAttributes
(
/** layout 布局配置**/
attrs
,
R
.
styleable
.
SectionItemView
,
/** 通过attr 设置**/
defStyleAttr
,
/** 默认样式 **/
0
);
int
type
=
a
.
getInteger
(
R
.
styleable
.
SectionItemView_type
,
0
);
switch
(
type
)
{
case
TYPE_ARROW:
{
}
case
TYPE_CHECK:
{
}
case
TYPE_RADIO:
{
}
}
a
.
recycle
();
}
}
widgetlib/src/main/java/com/qimai/android/widgetlib/popup/AbsQMBasePopup.kt
0 → 100644
View file @
e39c45b3
package
com.qimai.android.widgetlib.popup
import
android.content.Context
import
android.graphics.Color
import
android.graphics.Point
import
android.graphics.drawable.ColorDrawable
import
android.graphics.drawable.Drawable
import
android.os.Build
import
android.view.*
import
android.widget.FrameLayout
import
android.widget.PopupWindow
/**
* created by wangwei ON 2019-08-22 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
abstract
class
AbsQMBasePopup
(
open
var
context
:
Context
)
{
private
var
mWindow
=
PopupWindow
()
private
lateinit
var
mRootViewWrapper
:
FrameLayout
private
lateinit
var
mWindowManager
:
WindowManager
protected
open
var
mDismissListener
:
PopupWindow
.
OnDismissListener
?
=
null
abstract
fun
config
():
WindowConfig
var
touchOutside
=
true
set
(
value
)
{
field
=
value
mWindow
.
isOutsideTouchable
=
value
}
fun
isShowing
():
Boolean
{
return
mWindow
.
isShowing
}
fun
build
():
AbsQMBasePopup
{
val
config
=
config
()
setContentView
(
contentView
=
config
.
mContentView
)
mWindow
.
width
=
config
.
mWindowWidth
mWindow
.
height
=
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
LOLLIPOP_MR1
)
{
mWindow
.
isAttachedInDecor
=
false
}
if
(
config
.
mBackground
==
null
)
{
mWindow
.
setBackgroundDrawable
(
ColorDrawable
(
Color
.
TRANSPARENT
))
}
else
{
mWindow
.
setBackgroundDrawable
(
config
.
mBackground
)
}
mWindow
.
isTouchable
=
true
mWindow
.
isFocusable
=
true
mWindow
.
isOutsideTouchable
=
config
.
isOutsideTouchable
// 在相关的View被移除时,window也自动移除。避免当Fragment退出后,Fragment中弹出的PopupWindow还存在于界面上。
config
.
mAnchorView
.
addOnAttachStateChangeListener
(
object
:
View
.
OnAttachStateChangeListener
{
override
fun
onViewAttachedToWindow
(
v
:
View
)
{
}
override
fun
onViewDetachedFromWindow
(
v
:
View
)
{
if
(
isShowing
())
{
dismiss
()
}
}
})
return
this
}
fun
dimBehind
(
dim
:
Float
)
{
if
(!
::
mWindowManager
.
isInitialized
)
mWindowManager
=
context
.
getSystemService
(
Context
.
WINDOW_SERVICE
)
as
WindowManager
if
(!
isShowing
())
{
throw
RuntimeException
(
"should call after method show() or in onShowEnd()"
)
}
val
decorView
=
getDecorView
()
if
(
decorView
!=
null
)
{
val
p
=
decorView
.
layoutParams
as
WindowManager
.
LayoutParams
p
.
flags
=
p
.
flags
or
WindowManager
.
LayoutParams
.
FLAG_DIM_BEHIND
p
.
dimAmount
=
dim
mWindowManager
.
updateViewLayout
(
decorView
,
p
)
}
}
protected
abstract
fun
onShowBegin
(
contentView
:
View
):
Point
protected
abstract
fun
onShowEnd
()
fun
dismiss
()
{
if
(
isShowing
())
mWindow
.
dismiss
()
}
fun
show
()
{
if
(!
isShowing
())
{
val
point
=
onShowBegin
(
config
().
mContentView
)
mWindow
.
showAtLocation
(
config
().
mAnchorView
,
config
().
mGravity
,
point
.
x
,
point
.
y
)
onShowEnd
()
}
}
fun
setContentView
(
contentView
:
View
)
{
mRootViewWrapper
=
FrameLayout
(
contentView
.
context
)
mRootViewWrapper
.
layoutParams
=
ViewGroup
.
LayoutParams
(
ViewGroup
.
LayoutParams
.
MATCH_PARENT
,
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
)
mRootViewWrapper
.
addView
(
contentView
)
mWindow
.
contentView
=
mRootViewWrapper
mWindow
.
setTouchInterceptor
(
View
.
OnTouchListener
{
v
,
event
->
if
(
event
.
action
==
MotionEvent
.
ACTION_OUTSIDE
)
{
mWindow
.
dismiss
()
return
@OnTouchListener
false
}
false
})
mWindow
.
setOnDismissListener
{
this
@AbsQMBasePopup
.
onDismiss
()
if
(
mDismissListener
!=
null
)
{
mDismissListener
!!
.
onDismiss
()
}
}
}
protected
fun
onDismiss
()
{}
private
fun
getDecorView
():
View
?
{
var
decorView
:
View
?
=
null
try
{
decorView
=
if
(
mWindow
.
background
==
null
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
M
)
{
mWindow
.
contentView
.
parent
as
View
}
else
{
mWindow
.
contentView
}
}
else
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
M
)
{
mWindow
.
contentView
.
parent
.
parent
as
View
}
else
{
mWindow
.
contentView
.
parent
as
View
}
}
}
catch
(
ignore
:
Exception
)
{
}
return
decorView
}
class
WindowConfig
{
var
mWindowWidth
=
ViewGroup
.
LayoutParams
.
MATCH_PARENT
var
mWindowHeight
=
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
var
mAnimationStyle
:
Int
=
-
1
var
mGravity
:
Int
=
Gravity
.
CENTER
var
mBackground
:
Drawable
?
=
null
lateinit
var
mContentView
:
View
lateinit
var
mAnchorView
:
View
var
isOutsideTouchable
=
true
}
}
\ No newline at end of file
widgetlib/src/main/java/com/qimai/android/widgetlib/popup/CommonPopWindow.kt
View file @
e39c45b3
...
...
@@ -4,7 +4,6 @@ import android.content.Context
import
android.graphics.Point
import
android.view.Gravity
import
android.view.View
import
android.view.ViewGroup
import
android.widget.PopupWindow
import
com.qimai.android.tools.dpTopx
import
com.qimai.android.tools.getScreenWidth
...
...
@@ -17,7 +16,7 @@ import com.qimai.android.tools.getScreenWidth
class
CommonPopWindow
private
constructor
(
override
var
context
:
Context
,
private
val
contentView
:
View
,
private
var
animationStyle
:
Int
,
private
var
animationStyle
s
:
Int
,
override
var
gravity
:
Int
,
override
var
mDismissListener
:
PopupWindow
.
OnDismissListener
?
...
...
@@ -28,13 +27,20 @@ class CommonPopWindow private constructor(
private
constructor
(
builder
:
Builder
)
:
this
(
context
=
builder
.
mContentView
.
context
,
contentView
=
builder
.
mContentView
,
animationStyle
=
builder
.
animationStyle
,
animationStyle
s
=
builder
.
animationStyle
,
gravity
=
builder
.
gravity
,
mDismissListener
=
builder
.
dismissListener
)
{
this
.
setContentView
(
contentView
)
this
.
setAnimatonStyle
(
animationStyle
)
setWindowWidth
(
getScreenWidth
(
contentView
.
context
)
-
context
.
dpTopx
(
30.0f
))
this
.
setAnimationStyle
(
animationStyles
)
if
(
builder
.
windowWidth
<
0
)
setWindowWidth
(
getScreenWidth
(
contentView
.
context
)
-
context
.
dpTopx
(
30.0f
))
else
setWindowWidth
(
builder
.
windowWidth
)
if
(
builder
.
windowHeight
>
0
)
{
setWindowHeight
(
builder
.
windowHeight
)
}
}
...
...
@@ -48,14 +54,22 @@ class CommonPopWindow private constructor(
internal
var
dismissListener
:
PopupWindow
.
OnDismissListener
?
=
null
internal
var
windowWidth
=
ViewGroup
.
LayoutParams
.
MATCH_PARENT
internal
var
windowHeight
=
ViewGroup
.
LayoutParams
.
WRAP_CONTENT
var
windowWidth
=
-
1
var
windowHeight
=
-
1
fun
configContentView
(
contentView
:
View
)
=
apply
{
this
.
mContentView
=
contentView
}
fun
configWidowWith
(
windowWidth
:
Int
)
=
apply
{
this
.
windowWidth
=
windowWidth
}
fun
configWidowHeight
(
windowHeight
:
Int
)
=
apply
{
this
.
windowHeight
=
windowHeight
}
fun
configGravity
(
gravity
:
Int
)
=
apply
{
this
.
gravity
=
gravity
...
...
widgetlib/src/main/java/com/qimai/android/widgetlib/popup/Loading.kt
0 → 100644
View file @
e39c45b3
package
com.qimai.android.widgetlib.popup
import
android.os.Bundle
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
com.qimai.android.widgetlib.R
import
kotlinx.android.synthetic.main.loading.view.*
/**
* created by wangwei ON 2019-10-21 email:wangwei_5521@163.com
* @version 1.1.1
* @Description
**/
class
Loading
:
androidx
.
fragment
.
app
.
DialogFragment
()
{
private
lateinit
var
rootView
:
View
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?
):
View
?
{
super
.
onCreateView
(
inflater
,
container
,
savedInstanceState
)
val
root
=
inflater
.
inflate
(
R
.
layout
.
loading
,
container
,
false
)
rootView
=
root
return
root
}
fun
changeLoadText
(
loadingText
:
String
)
{
rootView
.
text
.
text
=
loadingText
}
fun
show
(
manager
:
androidx
.
fragment
.
app
.
FragmentManager
)
{
show
(
manager
,
"loading"
)
}
}
\ No newline at end of file
widgetlib/src/main/java/com/qimai/android/widgetlib/popup/QMBasePopup.kt
View file @
e39c45b3
...
...
@@ -39,7 +39,7 @@ abstract class QMBasePopup(open var context: Context) {
this
.
mWindowHeight
=
windowHeight
}
fun
setAnimatonStyle
(
style
:
Int
)
{
fun
setAnimat
i
onStyle
(
style
:
Int
)
{
mWindow
.
animationStyle
=
style
}
...
...
widgetlib/src/main/java/com/qimai/android/widgetlib/popup/QmAlertDialog.kt
View file @
e39c45b3
package
com.qimai.android.widgetlib.popup
import
android.content.Context
import
android.graphics.drawable.ColorDrawable
import
android.graphics.drawable.Drawable
import
android.text.TextUtils
import
android.view.Gravity
import
android.view.LayoutInflater
...
...
@@ -25,10 +23,11 @@ class QmAlertDialog private constructor(
private
val
subTitle
:
CharSequence
,
private
val
leftButtonText
:
String
,
private
val
rightButtonText
:
String
,
private
val
leftButtonClickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
,
private
val
rightButtonClickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
,
private
val
leftButtonClickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
,
private
val
rightButtonClickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
,
private
val
rootView
:
ViewGroup
,
private
val
dismissListener
:
PopupWindow
.
OnDismissListener
?
,
private
val
width
:
Int
)
{
private
lateinit
var
commonPopWindow
:
CommonPopWindow
...
...
@@ -41,7 +40,8 @@ class QmAlertDialog private constructor(
leftButtonClickListener
=
builder
.
leftButtonClick
,
rightButtonClickListener
=
builder
.
rightButtonClick
,
rootView
=
builder
.
rootView
,
dismissListener
=
builder
.
dismissListener
dismissListener
=
builder
.
dismissListener
,
width
=
builder
.
width
)
fun
show
()
{
...
...
@@ -76,13 +76,17 @@ class QmAlertDialog private constructor(
this
.
rightButtonClickListener
.
invoke
(
commonPopWindow
)
}
commonPopWindow
=
CommonPopWindow
.
Builder
()
val
builder
=
CommonPopWindow
.
Builder
()
.
configGravity
(
Gravity
.
CENTER
)
.
configContentView
(
contentView
)
.
dismissListener
(
PopupWindow
.
OnDismissListener
{
dismissListener
?.
onDismiss
()
})
.
build
()
if
(
width
>
0
){
builder
.
configWidowWith
(
width
)
}
commonPopWindow
=
builder
.
build
()
}
commonPopWindow
.
show
(
rootView
)
commonPopWindow
.
dimBehind
(
0.5f
)
...
...
@@ -104,11 +108,12 @@ class QmAlertDialog private constructor(
internal
var
leftButtonText
=
"取消"
internal
var
rightButtonText
=
"确定"
internal
lateinit
var
leftButtonClick
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
internal
lateinit
var
rightButtonClick
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
internal
lateinit
var
leftButtonClick
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
internal
lateinit
var
rightButtonClick
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
private
lateinit
var
context
:
Context
internal
lateinit
var
rootView
:
ViewGroup
internal
var
dismissListener
:
PopupWindow
.
OnDismissListener
?
=
null
internal
var
width
:
Int
=
0
fun
withTitle
(
title
:
CharSequence
)
=
apply
{
...
...
@@ -132,13 +137,21 @@ class QmAlertDialog private constructor(
this
.
rootView
=
rootView
}
fun
withWidth
(
windowWidth
:
Int
)
=
apply
{
this
.
width
=
windowWidth
}
fun
build
():
QmAlertDialog
{
return
QmAlertDialog
(
this
)
}
fun
withLeftButton
(
leftButtonText
:
String
,
clickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
)
=
fun
withLeftButton
(
leftButtonText
:
String
,
clickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
)
=
apply
{
this
.
leftButtonText
=
leftButtonText
...
...
@@ -146,7 +159,10 @@ class QmAlertDialog private constructor(
}
fun
withRightButton
(
rightButtonText
:
String
,
clickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
)
=
apply
{
fun
withRightButton
(
rightButtonText
:
String
,
clickListener
:
(
CommonPopWindow
:
CommonPopWindow
)
->
Unit
)
=
apply
{
this
.
rightButtonText
=
rightButtonText
this
.
rightButtonClick
=
clickListener
...
...
widgetlib/src/main/java/com/qimai/android/widgetlib/toast/HolderContext.java
0 → 100644
View file @
e39c45b3
package
com
.
qimai
.
android
.
widgetlib
.
toast
;
import
android.content.Context
;
/**
* created by wangwei ON 2019-11-04 email:wangwei_5521@163.com
*
* @version 1.1.1
* @Description
**/
public
class
HolderContext
{
private
static
volatile
HolderContext
instance
;
public
static
HolderContext
getInstance
()
{
if
(
instance
==
null
)
{
synchronized
(
HolderContext
.
class
)
{
if
(
instance
==
null
)
{
instance
=
new
HolderContext
();
}
}
}
return
instance
;
}
public
static
Context
getContext
()
{
return
getInstance
().
holder
.
getContext
();
}
public
Holder
holder
;
public
void
register
(
Holder
holder
)
{
this
.
holder
=
holder
;
}
public
interface
Holder
{
Context
getContext
();
}
}
widgetlib/src/main/java/com/qimai/android/widgetlib/toast/ToastUtils.java
0 → 100644
View file @
e39c45b3
package
com
.
qimai
.
android
.
widgetlib
.
toast
;
import
android.graphics.PorterDuff
;
import
android.graphics.PorterDuffColorFilter
;
import
android.graphics.drawable.ColorDrawable
;
import
android.graphics.drawable.Drawable
;
import
android.os.Build
;
import
android.view.Gravity
;
import
android.view.View
;
import
android.widget.TextView
;
import
android.widget.Toast
;
/**
* created by wangwei ON 2019-11-04 email:wangwei_5521@163.com
*
* @version 1.1.1
* @Description
**/
public
class
ToastUtils
{
private
static
volatile
ToastUtils
instance
;
private
static
final
int
COLOR_DEFAULT
=
0xFEFFFFFF
;
private
static
volatile
Toast
mToast
;
private
int
sMsgTextSize
=
-
1
;
private
int
sMsgColor
=
COLOR_DEFAULT
;
private
int
sGravity
=
-
1
;
private
int
sBgColor
=
COLOR_DEFAULT
;
private
int
sBgResource
=
-
1
;
public
static
ToastUtils
getInstance
()
{
if
(
instance
==
null
)
{
synchronized
(
ToastUtils
.
class
)
{
if
(
instance
==
null
)
{
instance
=
new
ToastUtils
();
}
}
}
return
instance
;
}
public
void
showCenter
(
String
msg
)
{
getToast
().
setText
(
msg
);
mToast
.
setGravity
(
Gravity
.
CENTER
,
0
,
0
);
mToast
.
show
();
}
public
void
showTaost
(
CharSequence
msg
)
{
getToast
();
View
toastView
=
mToast
.
getView
();
TextView
message
=
toastView
.
findViewById
(
android
.
R
.
id
.
message
);
message
.
setText
(
msg
);
if
(
sMsgTextSize
!=
-
1
)
{
message
.
setTextSize
(
sMsgTextSize
);
}
if
(
sMsgColor
!=
COLOR_DEFAULT
)
{
message
.
setTextColor
(
sMsgColor
);
}
if
(
sGravity
!=
-
1
)
{
mToast
.
setGravity
(
sGravity
,
0
,
0
);
}
if
(
sBgResource
!=
-
1
)
{
toastView
.
setBackgroundResource
(
sBgResource
);
}
else
if
(
sBgColor
!=
COLOR_DEFAULT
)
{
Drawable
background
=
toastView
.
getBackground
();
if
(
background
!=
null
)
{
background
.
setColorFilter
(
new
PorterDuffColorFilter
(
sBgColor
,
PorterDuff
.
Mode
.
SRC_IN
)
);
}
else
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
JELLY_BEAN
)
{
toastView
.
setBackground
(
new
ColorDrawable
(
sBgColor
));
}
else
{
toastView
.
setBackgroundDrawable
(
new
ColorDrawable
(
sBgColor
));
}
}
}
mToast
.
show
();
}
public
ToastUtils
setsMsgTextSize
(
int
msgTextSize
)
{
sMsgTextSize
=
msgTextSize
;
return
this
;
}
public
ToastUtils
setMsgColor
(
int
color
)
{
this
.
sMsgColor
=
color
;
return
this
;
}
public
ToastUtils
setGravity
(
int
gravity
)
{
this
.
sGravity
=
gravity
;
return
this
;
}
public
ToastUtils
setBgColor
(
int
color
)
{
this
.
sBgColor
=
color
;
return
this
;
}
public
ToastUtils
setBgResouce
(
int
bgResouce
)
{
this
.
sBgColor
=
bgResouce
;
return
this
;
}
private
static
Toast
getToast
()
{
if
(
mToast
==
null
)
{
synchronized
(
ToastUtils
.
class
)
{
if
(
mToast
==
null
)
{
mToast
=
Toast
.
makeText
(
HolderContext
.
getContext
(),
""
,
Toast
.
LENGTH_LONG
);
}
}
}
return
mToast
;
}
}
widgetlib/src/main/res/layout/loading.xml
0 → 100644
View file @
e39c45b3
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"wrap_content"
android:background=
"@drawable/shape_alert_bg"
android:layout_gravity=
"center"
android:padding=
"16dp"
android:layout_height=
"wrap_content"
>
<com.github.ybq.android.spinkit.SpinKitView
android:id=
"@+id/spin_kit"
style=
"@style/SpinKitView.Large.FadingCircle"
android:layout_width=
"90dp"
android:layout_height=
"90dp"
android:layout_gravity=
"center"
app:SpinKit_Color=
"#E2CE22"
/>
<TextView
android:id=
"@+id/text"
android:text=
"加载中..."
android:textColor=
"@color/color_222222"
android:textSize=
"15sp"
android:layout_marginTop=
"16dp"
android:layout_gravity=
"center"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
/>
</LinearLayout>
\ No newline at end of file
widgetlib/src/main/res/layout/section_itemview.xml
0 → 100644
View file @
e39c45b3
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:orientation=
"vertical"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
</LinearLayout>
\ No newline at end of file
widgetlib/src/main/res/values/attrs.xml
View file @
e39c45b3
...
...
@@ -36,4 +36,12 @@
<attr
name=
"overlay_borderColor"
format=
"color"
/>
<attr
name=
"overlay_borderWidth"
format=
"dimension"
/>
</declare-styleable>
<declare-styleable
name=
"SectionItemView"
>
<attr
name=
"type"
format=
"enum"
>
<enum
name=
"arrow"
value=
"0"
/>
<enum
name=
"check"
value=
"1"
/>
<enum
name=
"radio"
value=
"2"
/>
</attr>
</declare-styleable>
</resources>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment