Repository: long8313002/SuperXml
Branch: master
Commit: 010f20792c11
Files: 65
Total size: 78.3 KB
Directory structure:
gitextract_c62faek5/
├── .gitignore
├── .idea/
│ ├── codeStyles/
│ │ ├── Project.xml
│ │ └── codeStyleConfig.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── runConfigurations.xml
│ └── vcs.xml
├── README.md
├── app/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── zhangzheng/
│ │ └── superxml/
│ │ └── demo/
│ │ └── ExampleInstrumentedTest.kt
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── zhangzheng/
│ │ │ └── superxml/
│ │ │ └── demo/
│ │ │ ├── MApplication.kt
│ │ │ └── MainActivity.kt
│ │ └── res/
│ │ ├── drawable/
│ │ │ └── ic_launcher_background.xml
│ │ ├── drawable-v24/
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── layout/
│ │ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26/
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ └── values/
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── zhangzheng/
│ └── superxml/
│ └── demo/
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle/
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── library/
│ ├── .gitignore
│ ├── build.gradle
│ ├── consumer-rules.pro
│ ├── proguard-rules.pro
│ └── src/
│ ├── androidTest/
│ │ └── java/
│ │ └── com/
│ │ └── zhangzheng/
│ │ └── superxml/
│ │ └── library/
│ │ └── ExampleInstrumentedTest.kt
│ ├── main/
│ │ ├── AndroidManifest.xml
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── zhangzheng/
│ │ │ └── superxml/
│ │ │ └── library/
│ │ │ ├── LayoutInflateFactoryProxy.kt
│ │ │ ├── SuperXml.kt
│ │ │ ├── ViewDecorateManager.kt
│ │ │ ├── decorate/
│ │ │ │ ├── BackgroundEnableDecorate.kt
│ │ │ │ ├── BackgroundPressedDecorate.kt
│ │ │ │ ├── BackgroundSelectedDecorate.kt
│ │ │ │ ├── BorderDecorate.kt
│ │ │ │ ├── IDecorateView.kt
│ │ │ │ ├── RadiusDecorate.kt
│ │ │ │ ├── SrcRadiusDecorate.kt
│ │ │ │ ├── TextColorEnableDecorate.kt
│ │ │ │ ├── TextColorPresenterDecorate.kt
│ │ │ │ ├── TextColorSelectedDecorate.kt
│ │ │ │ └── wrap/
│ │ │ │ ├── CoverChildrenWrapDecorate.kt
│ │ │ │ ├── DottedLineWrapDecorate.kt
│ │ │ │ ├── IWrapDecorateView.kt
│ │ │ │ ├── ScrollWrapDecorate.kt
│ │ │ │ └── coverchildren/
│ │ │ │ ├── AbsChildViewParse.kt
│ │ │ │ ├── CoverChildrenLayout.kt
│ │ │ │ ├── ImageViewCoverParse.kt
│ │ │ │ └── TextViewCoverParse.kt
│ │ │ ├── ext/
│ │ │ │ ├── ViewBorderExt.kt
│ │ │ │ └── ViewRadiusExt.kt
│ │ │ └── view/
│ │ │ └── DottedLineView.kt
│ │ └── res/
│ │ └── values/
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test/
│ └── java/
│ └── com/
│ └── zhangzheng/
│ └── superxml/
│ └── library/
│ └── ExampleUnitTest.kt
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
================================================
FILE: .idea/codeStyles/Project.xml
================================================
.*:id
http://schemas.android.com/apk/res/android
.*:name
http://schemas.android.com/apk/res/android
.*
http://schemas.android.com/apk/res/android
ANDROID_ATTRIBUTE_ORDER
================================================
FILE: .idea/codeStyles/codeStyleConfig.xml
================================================
================================================
FILE: .idea/gradle.xml
================================================
================================================
FILE: .idea/misc.xml
================================================
================================================
FILE: .idea/runConfigurations.xml
================================================
================================================
FILE: .idea/vcs.xml
================================================
================================================
FILE: README.md
================================================
# android布局能力增加,轻松实现圆角、边框、虚线、属性覆盖等功能。完全无侵入
有排版: https://blog.csdn.net/long8313002/article/details/108703057
概述
android开发中,我们常常使用xml来写布局文件,这种实现方式不仅简单,而且表达能力更强。但是google提供的布局属性有限,有些功能的实现我们不得不使用代码,或者自定义控件的方式来实现。那有没有一种方法,可以将属性增强来实现额外的功能呢?例如我们常常使用background 来表示和设置背景,那是不是可以使用layout_radius来表示和设置圆角呢?
使用示例
需要在项目build.gradle中引用依赖
implementation 'com.zhangzheng.superxml:library:1.1.0'
另外在Application注册一行代码
SuperXml.init(this)
OVER
能力说明
属性增强
圆角:
说明
app:layout_radius 支持将控件背景设置为圆角,背景支持纯色背景或者图片,另外对于ImageView 的src如果想设置成圆角需要使用app:layout_src_radius,例如
复合属性
说明
一般情况下,我们要表示点击和普通状态下不同的字体颜色,或者背景会使用selector来定义一个文件,然后在布局文件中引用,一方面这样的使用很麻烦,另外一方面可读性也会降低(用户需要进入selector文件进行分析,才知道代码表达意图)。这边封装了常用的复用属性,如下:
属性 属性类型 说明
layout_background_enableTrue
layout_background_enableFalse
reference|color(资源或者颜色)
背景(是否可用)
layout_background_pressedTrue
layout_background_pressedFalse
reference|color(资源或者颜色) 背景(是否按压)
layout_background_selectedTrue
layout_background_selectedTrue
reference|color(资源或者颜色) 背景(是否选择)
layout_textColor_enableTrue
layout_textColor_enableFalse
reference|color(资源或者颜色) 字体颜色(是否可用)
layout_textColor_pressedTrue
layout_textColor_pressedFalse
reference|color(资源或者颜色) 字体颜色(是否按压)
layout_textColor_selectedTrue
layout_textColor_selectedFalse
reference|color(资源或者颜色) 字体颜色(是否选择)
边框
说明
比较简单,layout_border_color表示边框颜色,layout_border_width表示边框粗细,和radius一起使用表示边框圆角。
虚线
说明
可以在任何视图上使用(建议在View中定义),必须同时定义grap、dash_height、dash_width。支持横虚线,和竖虚线,这里会检测视图宽高来确定。属性说明:dash_grap(虚线间距)、dash_width(单个小线的宽)、dash_height(单个小线的高)
视图替换或增强
这个能力可能会将布局文件中的视图替换成其他控件、或者对其进行增强。
滚动视图
为了适配小屏手机,我们可能会在每一个布局文件中加上一层ScrollView,现在对容器控件进行能力增强。
说明
在需要滚动的视图上添加属性app:layout_canScroll="true",来使其获得滚动的能力。另外所有scrollView的属性,可以配置在该容器控件中。
属性覆盖
有一种很常见的业务场景,在一个条目中有多个控件,控件大多数属性是相同的(例如TextView的字体颜色、大小等),一般我们会给每一个控件加上相同的属性(冗余)、或者定义公共样式(太麻烦)。现在参考html的布局方式,在父控件中设置公共样式,给子控件当默认值。
支持的属性
控件类型 属性
TextView
textColor
textSize
text
maxLines
maxEms
textColorHint
hint
textDirection
textStyle
capitalize
ImageView
src
scaleType
扩展
属性扩展
SuperXml.addDecorate(object : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
}
override fun decorate(view: View) {
}
})
实现参考
internal class RadiusDecorate(var radius: Float = 0f) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
radius = typedArray.getDimension(R.styleable.decorate_view_layout_radius,0f)
return radius > 0
}
override fun decorate(view: View)= view.setRadius(radius)
}
控件替换 OR 增强
SuperXml.addDecorate(object :IWrapDecorateView(){
override fun decorateView(view: View): View {
}
override fun initExtraInfo(typedArray: TypedArray): Boolean {
}
})
实现参考
internal class ScrollWrapDecorate(var canScroll: Boolean = false) : IWrapDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
canScroll = typedArray.getBoolean(R.styleable.decorate_view_layout_canScroll, false)
return canScroll
}
override fun decorateView(view: View): View {
return ScrollViewProxy(
view,
attributeSet
)
}
}
属性覆盖
SuperXml.addCoverAttributeParse(object : AbsChildViewParse(){
override fun createInfoView(context: Context, attributeSet: AttributeSet?): TextView {
}
override fun coverAttribute(): MutableList<*> {
}
})
实现参考
class TextViewCoverParse : AbsChildViewParse() {
override fun createInfoView(context: Context, attributeSet: AttributeSet?): TextView =
TextView(context, attributeSet)
override fun coverAttribute(): MutableList<*> = mutableListOf(
AttributeInfo("textSize",{ textSize }) { value -> textSize = value },
AttributeInfo("textColor",{ textColors }) { value -> setTextColor(value) },
AttributeInfo("text",{ text }) { text -> setText(text) },
AttributeInfo("maxLines",{ maxLines }) { maxLines -> setMaxLines(maxLines) },
AttributeInfo("maxEms",{ maxEms }) { maxEms -> setMaxEms(maxEms) },
AttributeInfo("textColorHint",{ hintTextColors }) { hintTextColors -> setHintTextColor(hintTextColors) },
AttributeInfo("hint",{ hint }) { hint -> setHint(hint) },
AttributeInfo("textDirection",{ textDirection }) { textDirection -> setTextDirection(textDirection) },
AttributeInfo("textStyle",{ typeface }) { typeface -> setTypeface(typeface) },
AttributeInfo("capitalize",{ inputType }) { inputType -> setInputType(inputType) }
)
}
代码:github
https://github.com/long8313002/SuperXml
================================================
FILE: app/.gitignore
================================================
/build
================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.zhangzheng.superxml.demo"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
kotlinOptions.freeCompilerArgs += ['-module-name', "com.zhangzheng.superxml"]
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation project(":library")
}
================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app/src/androidTest/java/com/zhangzheng/superxml/demo/ExampleInstrumentedTest.kt
================================================
package com.zhangzheng.superxml.demo
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.zhangzheng.superxml.demo", appContext.packageName)
}
}
================================================
FILE: app/src/main/AndroidManifest.xml
================================================
================================================
FILE: app/src/main/java/com/zhangzheng/superxml/demo/MApplication.kt
================================================
package com.zhangzheng.superxml.demo
import android.app.Application
import com.zhangzheng.superxml.library.SuperXml
class MApplication : Application() {
override fun onCreate() {
super.onCreate()
SuperXml.init(this)
}
}
================================================
FILE: app/src/main/java/com/zhangzheng/superxml/demo/MainActivity.kt
================================================
package com.zhangzheng.superxml.demo
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.zhangzheng.superxml.library.ext.setBorder
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
================================================
FILE: app/src/main/res/drawable/ic_launcher_background.xml
================================================
================================================
FILE: app/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
================================================
FILE: app/src/main/res/values/colors.xml
================================================
#008577
#00574B
#D81B60
================================================
FILE: app/src/main/res/values/strings.xml
================================================
SuperXml
================================================
FILE: app/src/main/res/values/styles.xml
================================================
================================================
FILE: app/src/test/java/com/zhangzheng/superxml/demo/ExampleUnitTest.kt
================================================
package com.zhangzheng.superxml.demo
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.0'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Wed Sep 16 13:39:55 CST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
================================================
FILE: gradlew
================================================
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
================================================
FILE: library/.gitignore
================================================
/build
================================================
FILE: library/build.gradle
================================================
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
buildToolsVersion "30.0.2"
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
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'
}
}
compileOptions {
kotlinOptions.freeCompilerArgs += ['-module-name', "com.zhangzheng.superxml"]
}
}
dependencies {
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
/** 以下开始是将Android Library上传到JCenter的相关配置**/
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
//项目主页
def siteUrl = 'https://github.com/long8313002/SuperXml'
//项目的版本控制地址
def gitUrl = 'https://github.com/long8313002/SuperXml'
//发布到组织名称名字,必须填写
group = "com.zhangzheng.superxml"
//发布到JCenter上的项目名字,必须填写
def libName = "SuperXml"
// 版本号,下次更新是只需要更改版本号即可
version = "1.1.4"
/** 上面配置后上传至JCenter后的编译路径是这样的: compile 'group:libName:version' **/
//生成源文件
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
//生成文档
task javadoc(type: Javadoc) {
source = android.sourceSets.main.java.srcDirs
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
options.encoding "UTF-8"
options.charSet 'UTF-8'
options.author true
options.version true
options.links "https://github.com/long8313002/CrashProtect"
failOnError false
}
//文档打包成jar
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
//拷贝javadoc文件
task copyDoc(type: Copy) {
from "${buildDir}/docs/"
into "docs"
}
//上传到jCenter所需要的源码文件
artifacts {
archives javadocJar
archives sourcesJar
}
// 配置maven库,生成POM.xml文件
install {
repositories.mavenInstaller {
// This generates POM.xml with proper parameters
pom {
project {
packaging 'aar'
name 'SuperXml'
url siteUrl
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'zhangzheng'
name 'zhangzheng'
email 'zhangzheng@xyz.cn'
}
}
scm {
connection gitUrl
developerConnection gitUrl
url siteUrl
}
}
}
}
}
//上传到JCenter
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user") //读取 local.properties 文件里面的 bintray.user
key = properties.getProperty("bintray.apikey") //读取 local.properties 文件里面的 bintray.apikey
println("-----"+user+"-----"+key)
configurations = ['archives']
pkg {
repo = "maven"
name = libName //发布到JCenter上的项目名字,必须填写
desc = 'SuperXml' //项目描述
websiteUrl = siteUrl
vcsUrl = gitUrl
licenses = ["Apache-2.0"]
publish = true
}
}
================================================
FILE: library/consumer-rules.pro
================================================
================================================
FILE: library/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: library/src/androidTest/java/com/zhangzheng/superxml/library/ExampleInstrumentedTest.kt
================================================
package com.zhangzheng.superxml.library
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.Assert.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("com.zhangzheng.superxml.library.test", appContext.packageName)
}
}
================================================
FILE: library/src/main/AndroidManifest.xml
================================================
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/LayoutInflateFactoryProxy.kt
================================================
package com.zhangzheng.superxml.library
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import java.lang.Exception
internal class LayoutInflateFactoryProxy(layoutInflater: LayoutInflater, private var service:IService ): LayoutInflater.Factory2 {
interface IService {
fun hasDecorate(attrs: AttributeSet): Boolean
fun decorate(view: View):View
}
private var factory = layoutInflater.factory
private var factory2 = layoutInflater.factory2
private var cloneLayoutInflate = layoutInflater.cloneInContext(layoutInflater.context)
override fun onCreateView(parent: View?, name: String?, context: Context?,
attrs: AttributeSet?): View? {
if(attrs==null||!service.hasDecorate(attrs)){
return null
}
var view = factory2?.onCreateView(parent, name, context, attrs)
if (view == null) {
view = factory?.onCreateView(name, context, attrs)
}
if (view == null) {
view = createView(name, null, attrs)
}
if (view == null) {
view = createView(name, "android.widget.", attrs)
}
if (view == null) {
view = createView(name, "android.view.", attrs)
}
if (view == null) {
view = compensateCreateView(name,context,attrs)
}
if (view != null) {
view = service.decorate(view)
}
return view
}
private fun compensateCreateView(name: String?, context: Context?, attrs: AttributeSet?): View? {
if (name == null || context == null || attrs == null) {
return null
}
var view = reflexCreateView(name, context, attrs)
if (view == null) {
view = reflexCreateView("android.widget.$name", context, attrs)
}
if (view == null) {
view = reflexCreateView("android.view.$name", context, attrs)
}
return view
}
private fun reflexCreateView(name: String, context: Context, attrs: AttributeSet): View? {
try {
val clazz = Class.forName(name)
val constructor = clazz.getConstructor(Context::class.java, AttributeSet::class.java)
return constructor.newInstance(context, attrs) as View
} catch (e: Exception) {
}
return null
}
private fun createView(name: String?, prefix: String?, attrs: AttributeSet?): View? {
return try {
cloneLayoutInflate.createView(name, prefix, attrs)
} catch (e: Exception) {
null
}
}
override fun onCreateView(name: String?, context: Context?, attrs: AttributeSet?) =
onCreateView(null, name, context, attrs)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/SuperXml.kt
================================================
package com.zhangzheng.superxml.library
import android.app.Activity
import android.app.Application
import android.os.Bundle
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import com.zhangzheng.superxml.library.decorate.IDecorateView
import com.zhangzheng.superxml.library.decorate.wrap.IWrapDecorateView
import com.zhangzheng.superxml.library.decorate.wrap.coverchildren.IChildViewParse
import com.zhangzheng.superxml.library.decorate.wrap.coverchildren.addCoverChildViewParse
object SuperXml {
fun addDecorate(decorate: IWrapDecorateView) = ViewDecorateManager.addDecorate(decorate)
fun addDecorate(decorate: IDecorateView) = ViewDecorateManager.addDecorate(decorate)
fun addCoverAttributeParse(parse: IChildViewParse){
addCoverChildViewParse(parse)
}
fun init(app: Application) {
app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(p0: Activity, p1: Bundle?) = hookActivityLayout(p0)
override fun onActivityPaused(p0: Activity) = Unit
override fun onActivityStarted(p0: Activity) = Unit
override fun onActivityDestroyed(p0: Activity) = Unit
override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) = Unit
override fun onActivityStopped(p0: Activity) = Unit
override fun onActivityResumed(p0: Activity) = Unit
})
}
private fun hookActivityLayout(activity: Activity) {
val layoutInflater = LayoutInflater.from(activity)
setLayoutInflateAllowState(layoutInflater, true)
layoutInflater.factory2 =
LayoutInflateFactoryProxy(layoutInflater, object : LayoutInflateFactoryProxy.IService {
override fun hasDecorate(attrs: AttributeSet) =
ViewDecorateManager.hasDecorate(activity, attrs)
override fun decorate(view: View) = ViewDecorateManager.decorate(view)
})
setLayoutInflateAllowState(layoutInflater, false)
}
private fun setLayoutInflateAllowState(layoutInflater: LayoutInflater, isAllow: Boolean) {
val mFactorySet = LayoutInflater::class.java.getDeclaredField("mFactorySet")
mFactorySet.isAccessible = true
mFactorySet.set(layoutInflater, !isAllow)
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/ViewDecorateManager.kt
================================================
package com.zhangzheng.superxml.library
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.View
import com.zhangzheng.superxml.library.decorate.*
import com.zhangzheng.superxml.library.decorate.RadiusDecorate
import com.zhangzheng.superxml.library.decorate.SrcRadiusDecorate
import com.zhangzheng.superxml.library.decorate.wrap.CoverChildrenWrapDecorate
import com.zhangzheng.superxml.library.decorate.wrap.DottedLineWrapDecorate
import com.zhangzheng.superxml.library.decorate.wrap.IWrapDecorateView
import com.zhangzheng.superxml.library.decorate.wrap.ScrollWrapDecorate
internal object ViewDecorateManager {
private val decorateList = arrayListOf(
RadiusDecorate(),
SrcRadiusDecorate(),
BackgroundPressedDecorate(),
BackgroundSelectedDecorate(),
BackgroundEnableDecorate(),
TextColorEnableDecorate(),
TextColorPresenterDecorate(),
TextColorSelectedDecorate(),
BorderDecorate()
)
private val wrapDecorateList = arrayListOf(
ScrollWrapDecorate(),
DottedLineWrapDecorate(),
CoverChildrenWrapDecorate()
)
fun addDecorate(decorate: IWrapDecorateView){
wrapDecorateList.add(decorate)
}
fun addDecorate(decorate:IDecorateView){
decorateList.add(decorate)
}
fun hasDecorate(context: Context, attributeSet: AttributeSet): Boolean {
val typedArray: TypedArray = context.obtainStyledAttributes(
attributeSet, R.styleable.decorate_view
)
var hasDecorateInfo = false
(decorateList + wrapDecorateList).forEach {
it.attributeSet = attributeSet
if (it.initExtraInfo(typedArray)) {
hasDecorateInfo = true
it.hasExtraInfo = true
} else {
it.hasExtraInfo = false
}
}
typedArray.recycle()
return hasDecorateInfo
}
fun decorate(view: View): View {
decorateList.forEach {
if (it.hasExtraInfo) {
it.decorate(view)
}
}
var wrapView = view
wrapDecorateList.forEach {
if (it.hasExtraInfo) {
wrapView = it.decorateView(wrapView)
}
}
return wrapView
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/BackgroundEnableDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.graphics.drawable.StateListDrawable
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.*
internal class BackgroundEnableDecorate(var drawable: StateListDrawable? = null) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val radius = typedArray.getDimension(R.styleable.decorate_view_layout_radius,0f)
val enable = createRadiusDrawable(radius,typedArray.getDrawable(
R.styleable.decorate_view_layout_background_enableTrue
))
val normal = createRadiusDrawable(radius,typedArray.getDrawable(
R.styleable.decorate_view_layout_background_enableFalse
))
if (enable == null || normal == null) {
return false
}
drawable = StateListDrawable()
drawable?.addState(intArrayOf(android.R.attr.state_enabled), enable)
drawable?.addState(intArrayOf(-android.R.attr.state_enabled), normal)
return true
}
override fun decorate(view: View) {
view.background = drawable
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/BackgroundPressedDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.graphics.drawable.StateListDrawable
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.createRadiusDrawable
internal class BackgroundPressedDecorate(var drawable: StateListDrawable? = null) :
IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val radius = typedArray.getDimension(R.styleable.decorate_view_layout_radius, 0f)
val press = createRadiusDrawable(
radius, typedArray.getDrawable(
R.styleable.decorate_view_layout_background_pressedTrue
)
)
val normal = createRadiusDrawable(
radius, typedArray.getDrawable(
R.styleable.decorate_view_layout_background_pressedFalse
)
)
if (press == null || normal == null) {
return false
}
drawable = StateListDrawable()
drawable?.addState(intArrayOf(android.R.attr.state_pressed), press)
drawable?.addState(intArrayOf(-android.R.attr.state_pressed), normal)
return true
}
override fun decorate(view: View) {
view.background = drawable
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/BackgroundSelectedDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.graphics.drawable.StateListDrawable
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.createRadiusDrawable
internal class BackgroundSelectedDecorate(var drawable: StateListDrawable? = null) :
IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val radius = typedArray.getDimension(R.styleable.decorate_view_layout_radius, 0f)
val selected = createRadiusDrawable(
radius, typedArray.getDrawable(
R.styleable.decorate_view_layout_background_selectedTrue
)
)
val normal = createRadiusDrawable(
radius, typedArray.getDrawable(
R.styleable.decorate_view_layout_background_selectedFalse
)
)
if (selected == null || normal == null) {
return false
}
drawable = StateListDrawable()
drawable?.addState(intArrayOf(android.R.attr.state_selected), selected)
drawable?.addState(intArrayOf(-android.R.attr.state_selected), normal)
return true
}
override fun decorate(view: View) {
view.background = drawable
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/BorderDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.setBorder
internal class BorderDecorate : IDecorateView() {
private var borderColor = 0
private var borderWidth = 0
override fun initExtraInfo(typedArray: TypedArray): Boolean {
borderWidth = typedArray.getDimension(
R.styleable.decorate_view_layout_border_width, 0f
).toInt()
borderColor = typedArray.getColor(
R.styleable.decorate_view_layout_border_color, 0
)
return borderWidth != 0 && borderColor != 0
}
override fun decorate(view: View) {
view.setBorder(borderWidth,borderColor)
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/IDecorateView.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.util.AttributeSet
import android.view.View
abstract class IDecorateView {
var hasExtraInfo: Boolean = false
var attributeSet: AttributeSet? = null
/**
* 初始化解析额外添加的信息
* @return 是否包含额外信息
*/
abstract fun initExtraInfo(typedArray: TypedArray): Boolean
abstract fun decorate(view: View)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/RadiusDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.setRadius
internal class RadiusDecorate(var radius: Float = 0f) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
radius = typedArray.getDimension(R.styleable.decorate_view_layout_radius,0f)
return radius > 0
}
override fun decorate(view: View)= view.setRadius(radius)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/SrcRadiusDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.TypedArray
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.ext.setRadius
import com.zhangzheng.superxml.library.ext.setSrcRadius
internal class SrcRadiusDecorate(var radius: Float = 0f) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
radius = typedArray.getDimension(R.styleable.decorate_view_layout_src_radius,0f)
return radius > 0
}
override fun decorate(view: View)= view.setSrcRadius(radius)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/TextColorEnableDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.view.View
import android.widget.TextView
import com.zhangzheng.superxml.library.R
internal class TextColorEnableDecorate(var color: ColorStateList? = null) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val enable = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_enableTrue,0)
val normal = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_enableFalse,0)
if (enable == 0 || normal == 0) {
return false
}
val states = arrayOfNulls(2)
states[0] = intArrayOf(android.R.attr.state_enabled)
states[1] = intArrayOf(-android.R.attr.state_enabled)
color = ColorStateList(states, intArrayOf(enable,normal))
return true
}
override fun decorate(view: View) {
if(view is TextView){
view.setTextColor(color)
}
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/TextColorPresenterDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.view.View
import android.widget.TextView
import com.zhangzheng.superxml.library.R
internal class TextColorPresenterDecorate(var color: ColorStateList? = null) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val pressed = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_pressedTrue,0)
val normal = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_pressedFalse,0)
if (pressed == 0 || normal == 0) {
return false
}
val states = arrayOfNulls(2)
states[0] = intArrayOf(android.R.attr.state_pressed)
states[1] = intArrayOf(-android.R.attr.state_pressed)
color = ColorStateList(states, intArrayOf(pressed,normal))
return true
}
override fun decorate(view: View) {
if(view is TextView){
view.setTextColor(color)
}
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/TextColorSelectedDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.view.View
import android.widget.TextView
import com.zhangzheng.superxml.library.R
internal class TextColorSelectedDecorate(var color: ColorStateList? = null) : IDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
val selected = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_selectedTrue,0)
val normal = typedArray.getColor(
R.styleable.decorate_view_layout_textColor_selectedFalse,0)
if (selected == 0 || normal == 0) {
return false
}
val states = arrayOfNulls(2)
states[0] = intArrayOf(android.R.attr.state_selected)
states[1] = intArrayOf(-android.R.attr.state_selected)
color = ColorStateList(states, intArrayOf(selected,normal))
return true
}
override fun decorate(view: View) {
if(view is TextView){
view.setTextColor(color)
}
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/CoverChildrenWrapDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap
import android.content.res.TypedArray
import android.view.View
import android.view.ViewGroup
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.decorate.wrap.coverchildren.CoverChildrenLayout
class CoverChildrenWrapDecorate : IWrapDecorateView() {
override fun initExtraInfo(typedArray: TypedArray) =
typedArray.getBoolean(R.styleable.decorate_view_layout_cover_children, false)
override fun decorateView(view: View) =
if (view !is ViewGroup) {
view
} else {
CoverChildrenLayout(view, attributeSet)
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/DottedLineWrapDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap
import android.content.res.TypedArray
import android.view.View
import com.zhangzheng.superxml.library.R
import com.zhangzheng.superxml.library.view.DottedLineView
class DottedLineWrapDecorate : IWrapDecorateView() {
override fun initExtraInfo(typedArray: TypedArray)=
typedArray.getDimension(R.styleable.decorate_view_layout_dash_height, 0f) > 0
&& typedArray.getDimension(R.styleable.decorate_view_layout_dash_width, 0f) > 0
override fun decorateView(view: View): View {
return DottedLineView(view.context, attributeSet).also {
it.id = view.id
}
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/IWrapDecorateView.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap
import android.view.View
import com.zhangzheng.superxml.library.decorate.IDecorateView
abstract class IWrapDecorateView :
IDecorateView(){
override fun decorate(view: View) =Unit
abstract fun decorateView(view: View):View
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/ScrollWrapDecorate.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap
import android.content.res.TypedArray
import android.graphics.Color
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.ScrollView
import com.zhangzheng.superxml.library.R
private class ScrollViewProxy(val view: View,attributeSet: AttributeSet?) : ScrollView(view.context,attributeSet) {
init {
setBackgroundColor(Color.TRANSPARENT)
}
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
if (child?.parent != null) {
return
}
if (child == view) {
super.addView(child, index, params)
} else if (view is ViewGroup) {
view.addView(child, index, params)
}
}
override fun onFinishInflate() {
super.onFinishInflate()
addView(view)
id = R.id.decorateScrollView
}
}
internal class ScrollWrapDecorate(var canScroll: Boolean = false) : IWrapDecorateView() {
override fun initExtraInfo(typedArray: TypedArray): Boolean {
canScroll = typedArray.getBoolean(R.styleable.decorate_view_layout_canScroll, false)
return canScroll
}
override fun decorateView(view: View): View {
return ScrollViewProxy(
view,
attributeSet
)
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/coverchildren/AbsChildViewParse.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap.coverchildren
import android.content.Context
import android.util.AttributeSet
import android.view.View
abstract class AbsChildViewParse : IChildViewParse {
inner class AttributeInfo(
var name: String,
var getAttr: T.() -> M,
var setAttr: T.(value: M) -> Unit
)
private lateinit var infoView: T
private lateinit var coverAttribute: MutableList<*>
private lateinit var updateAttribute: MutableList<*>
protected lateinit var context:Context
override fun init(context: Context) {
this.context = context
}
override fun parentAttribute(attributeSet: AttributeSet?) {
infoView = createInfoView(context, attributeSet)
coverAttribute = coverAttribute()
filterAttribute(coverAttribute,attributeSet, false)
}
private fun filterAttribute(attributeList: MutableList<*>, attributeSet: AttributeSet?, hasAttrFilter: Boolean) {
val iterator = attributeList.iterator()
while (iterator.hasNext()) {
val item = iterator.next() as AttributeInfo
val name = item.name
if ((hasAttrFilter && hasAttribute(attributeSet, name))
|| (!hasAttrFilter && !hasAttribute(attributeSet, name))
) {
iterator.remove()
}
}
}
private fun hasAttribute(attributeSet: AttributeSet?, name: String): Boolean {
val nameSpace = "http://schemas.android.com/apk/res/android"
return attributeSet?.getAttributeValue(nameSpace, name)?.isNotEmpty() == true
}
override fun childAttribute(childViewAttr: AttributeSet?) {
updateAttribute = ArrayList(coverAttribute)
filterAttribute(updateAttribute,childViewAttr, true)
}
abstract fun createInfoView(context: Context, attributeSet: AttributeSet?): T
abstract fun coverAttribute(): MutableList<*>
override fun updateChildView(childView: View) {
updateAttribute.forEach {
try {
it as AttributeInfo
val value = it.getAttr(infoView)
it.setAttr(childView as T, value)
}catch (e:ClassCastException){
}
}
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/coverchildren/CoverChildrenLayout.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap.coverchildren
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
interface IChildViewParse {
fun init(context: Context)
fun parentAttribute(attributeSet: AttributeSet?)
fun childAttribute(childViewAttr: AttributeSet?)
fun updateChildView(view: View)
}
private val childViewParseList = mutableListOf(
TextViewCoverParse(),
ImageViewCoverParse()
)
fun addCoverChildViewParse(parse:IChildViewParse){
childViewParseList.add(parse)
}
class CoverChildrenLayout(var baseView: ViewGroup, attributeSet: AttributeSet?) : FrameLayout(baseView.context) {
init {
childViewParseList.forEach { it.init(context) }
childViewParseList.forEach { it.parentAttribute(attributeSet) }
}
override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
baseView.addView(child, index, params)
childViewParseList.forEach {
if (child != null) {
it.updateChildView(child)
}
}
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
(parent as ViewGroup).addView(baseView, removeSelf())
}
override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
childViewParseList.forEach { it.childAttribute(attrs) }
return super.generateLayoutParams(attrs)
}
private fun removeSelf(): Int {
val parent = parent as ViewGroup
var index = 0
for (i in 0 until parent.childCount) {
if (parent.getChildAt(i) == this) {
parent.removeView(this)
break
}
index++
}
return index
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/coverchildren/ImageViewCoverParse.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap.coverchildren
import android.content.Context
import android.util.AttributeSet
import android.widget.ImageView
class ImageViewCoverParse : AbsChildViewParse() {
override fun createInfoView(context: Context, attributeSet: AttributeSet?) = ImageView(context,attributeSet)
override fun coverAttribute(): MutableList<*> = mutableListOf(
AttributeInfo("src",{ drawable }) { drawable -> setImageDrawable(drawable) },
AttributeInfo("scaleType",{ scaleType }) { scaleType -> setScaleType(scaleType) }
)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/decorate/wrap/coverchildren/TextViewCoverParse.kt
================================================
package com.zhangzheng.superxml.library.decorate.wrap.coverchildren
import android.content.Context
import android.util.AttributeSet
import android.widget.TextView
class TextViewCoverParse : AbsChildViewParse() {
override fun createInfoView(context: Context, attributeSet: AttributeSet?): TextView =
TextView(context, attributeSet)
override fun coverAttribute(): MutableList<*> = mutableListOf(
AttributeInfo("textSize",{ textSize }) { value -> textSize = value },
AttributeInfo("textColor",{ textColors }) { value -> setTextColor(value) },
AttributeInfo("text",{ text }) { text -> setText(text) },
AttributeInfo("maxLines",{ maxLines }) { maxLines -> setMaxLines(maxLines) },
AttributeInfo("maxEms",{ maxEms }) { maxEms -> setMaxEms(maxEms) },
AttributeInfo("textColorHint",{ hintTextColors }) { hintTextColors -> setHintTextColor(hintTextColors) },
AttributeInfo("hint",{ hint }) { hint -> setHint(hint) },
AttributeInfo("textDirection",{ textDirection }) { textDirection -> setTextDirection(textDirection) },
AttributeInfo("textStyle",{ typeface }) { typeface -> setTypeface(typeface) },
AttributeInfo("capitalize",{ inputType }) { inputType -> setInputType(inputType) }
)
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/ext/ViewBorderExt.kt
================================================
package com.zhangzheng.superxml.library.ext
import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.view.View
fun View.setBorder(width: Int, color: Int) {
background = getBorderBg(this, width, color)
}
private fun getBorderBg(view: View, width: Int, color: Int): Drawable {
if (view.background !is ColorDrawable && view.background !is GradientDrawable) {
return view.background
}
val drawable = if (view.background is GradientDrawable) {
view.background as GradientDrawable
} else GradientDrawable().also {
it.color = ColorStateList.valueOf((view.background as ColorDrawable).color)
}
return drawable.also {
it.setStroke(width, color)
}
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/ext/ViewRadiusExt.kt
================================================
package com.zhangzheng.superxml.library.ext
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.view.View
import android.widget.ImageView
fun View.setRadius(radius: Float) {
val backgroundColor = getBackgroundColor(this)
val background = getBackground(this)
if (backgroundColor != null) {
this.background = getRoundRectBgByColorValue( backgroundColor, radius)
}else if(background!=null){
this.background = BitmapDrawable(toRoundCorner(background,radius))
}
}
fun View.setSrcRadius(radius: Float){
if(this is ImageView){
val src = drawable
if(src is BitmapDrawable){
setImageBitmap(toRoundCorner(src.bitmap,radius))
}
}
}
internal fun createRadiusDrawable(radius: Float,drawable: Drawable?):Drawable?{
if(drawable is ColorDrawable){
return getRoundRectBgByColorValue( drawable.color, radius)
}
if(drawable is BitmapDrawable){
return BitmapDrawable(toRoundCorner(drawable.bitmap,radius))
}
return drawable
}
private fun getRoundRectBgByColorValue( color: Int, radius: Float) :Drawable{
return GradientDrawable().also {
it.shape = GradientDrawable.RECTANGLE
it.cornerRadius = radius
it.setColor(color)
}
}
private fun getBackgroundColor(view: View): Int? {
var bgColor: Int? = null
if (view.background is ColorDrawable) {
val colorDrawable = view.background as ColorDrawable
bgColor = colorDrawable.color
}
return bgColor
}
private fun getBackground(view: View): Bitmap? {
val background = view.background
return if (background is BitmapDrawable) {
background.bitmap
} else {
null
}
}
private fun toRoundCorner(bitmap: Bitmap, pixels: Float): Bitmap? {
val output =
Bitmap.createBitmap(bitmap.width, bitmap.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(output)
val paint = Paint()
val rect = Rect(0, 0, bitmap.width, bitmap.height)
val rectF = RectF(rect)
paint.isAntiAlias = true
canvas.drawARGB(0, 0, 0, 0)
canvas.drawRoundRect(rectF, pixels/2, pixels/2, paint)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
canvas.drawBitmap(bitmap, rect, rect, paint)
return output
}
================================================
FILE: library/src/main/java/com/zhangzheng/superxml/library/view/DottedLineView.kt
================================================
package com.zhangzheng.superxml.library.view
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.util.AttributeSet
import android.view.View
import com.zhangzheng.superxml.library.R
internal class DottedLineView : View {
private var dashWidth = 0
private var dashHeight = 0
private var dashGap = 0
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {
val typedArray: TypedArray =
context!!.obtainStyledAttributes(attrs, R.styleable.decorate_view)
dashWidth = typedArray.getDimension(
R.styleable.decorate_view_layout_dash_width, 0f
).toInt()
dashHeight = typedArray.getDimension(
R.styleable.decorate_view_layout_dash_height, 0f
).toInt()
dashGap = typedArray.getDimension(
R.styleable.decorate_view_layout_dash_gap, 0f
).toInt()
typedArray.recycle()
}
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun onDraw(canvas: Canvas) {
background.setBounds(0, 0, dashWidth, dashHeight)
background.draw(canvas)
if (width > height) {
var translateX = 0
while (translateX <= width) {
canvas.translate((dashWidth + dashGap).toFloat(), 0f)
background.draw(canvas)
translateX += dashWidth + dashGap
}
}else{
var translateY = 0
while (translateY <= height) {
canvas.translate(0f, (dashHeight + dashGap).toFloat())
background.draw(canvas)
translateY += dashHeight + dashGap
}
}
}
}
================================================
FILE: library/src/main/res/values/ids.xml
================================================
================================================
FILE: library/src/main/res/values/strings.xml
================================================
library
================================================
FILE: library/src/main/res/values/styles.xml
================================================
================================================
FILE: library/src/test/java/com/zhangzheng/superxml/library/ExampleUnitTest.kt
================================================
package com.zhangzheng.superxml.library
import org.junit.Test
import org.junit.Assert.*
/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}
================================================
FILE: settings.gradle
================================================
include ':app', ':library'
rootProject.name='SuperXml'