Merge branch 'skin_custom_view' into dev

This commit is contained in:
wangcongtao
2020-09-03 14:29:17 +08:00
156 changed files with 11195 additions and 9 deletions

5
.idea/gradle.xml generated
View File

@@ -61,6 +61,11 @@
<option value="$PROJECT_DIR$/skin/mogo-skin-support" />
<option value="$PROJECT_DIR$/skin/mogo-skin-support-impl" />
<option value="$PROJECT_DIR$/skin/mogo-skin-support-noop" />
<option value="$PROJECT_DIR$/skin/skin-support" />
<option value="$PROJECT_DIR$/skin/skin-support-appcompat" />
<option value="$PROJECT_DIR$/skin/skin-support-cardview" />
<option value="$PROJECT_DIR$/skin/skin-support-constraint-layout" />
<option value="$PROJECT_DIR$/skin/skin-support-design" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />

2
.idea/misc.xml generated
View File

@@ -4,7 +4,7 @@
<asm skipDebug="false" skipFrames="false" skipCode="false" expandFrames="false" />
<groovy codeStyle="LEGACY" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
</project>

View File

@@ -0,0 +1,71 @@
package com.mogo.module.common.glide;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
public
/**
* @author congtaowang
* @since 2020/9/2
*
* 描述
*/
class SkinAbleBitmapTarget extends SimpleTarget< Bitmap > {
private ImageView mTarget;
private RequestOptions mOptions;
public SkinAbleBitmapTarget( ImageView mTarget, RequestOptions mOptions ) {
super();
this.mTarget = mTarget;
this.mOptions = mOptions;
}
@Override
public void onResourceReady( @NonNull Bitmap resource, @Nullable Transition< ? super Bitmap > transition ) {
try {
mTarget.setImageResource( 0 );
mTarget.setImageBitmap( resource );
} catch( Exception e ){
e.printStackTrace();
}
}
@Override
public void onLoadCleared( @Nullable Drawable placeholder ) {
super.onLoadCleared( placeholder );
try {
mTarget.setImageResource( mOptions.getPlaceholderId() );
} catch ( Exception e ) {
e.printStackTrace();
}
}
@Override
public void onLoadStarted( @Nullable Drawable placeholder ) {
super.onLoadStarted( placeholder );
try {
mTarget.setImageResource( mOptions.getPlaceholderId() );
} catch ( Exception e ) {
e.printStackTrace();
}
}
@Override
public void onLoadFailed( @Nullable Drawable errorDrawable ) {
super.onLoadFailed( errorDrawable );
try {
mTarget.setImageResource( mOptions.getErrorId() );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}

View File

@@ -19,13 +19,13 @@ import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.mogo.commons.debug.DebugConfig;
import com.mogo.module.common.entity.MarkerExploreWay;
import com.mogo.module.common.glide.SkinAbleBitmapTarget;
import com.mogo.module.tanlu.R;
import com.mogo.module.tanlu.callback.IThumbsUpCallback;
import com.mogo.module.tanlu.constant.TanluConstants;
import com.mogo.module.tanlu.model.TanluModelData;
import com.mogo.module.tanlu.model.event.CloseWindowInfo;
import com.mogo.module.tanlu.model.event.ControlClickUpInfo;
import com.mogo.module.tanlu.model.event.DataErrorInfo;
import com.mogo.module.tanlu.model.event.StartPlayInfo;
import com.mogo.module.tanlu.model.event.VoiceControlUpInfo;
import com.mogo.module.tanlu.util.ChartUtil;
@@ -372,9 +372,10 @@ public class TanluSlideAdapterNew extends RecyclerView.Adapter<TanluSlideViewHol
.error(R.drawable.tanlu_normal_image)
.fallback(R.drawable.tanlu_normal_image);
Glide.with(mContext)
.asBitmap()
.load(imageUrl)
.apply(requestOptions)
.into(autoZoomInImageView);
.into(new SkinAbleBitmapTarget(autoZoomInImageView, requestOptions));
}

View File

@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/tanlu_module_card_height"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/tanlu_gradual_change_bg">
<!--视频播放器和图片播放器-->
@@ -37,7 +38,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:src="@drawable/tanlu_normal_image"
tools:src="@drawable/tanlu_normal_image"
android:scaleType="fitXY" />
</com.mogo.module.tanlu.view.RoundLayout>

View File

@@ -1,3 +1,8 @@
include ':skin:skin-support'
include ':skin:skin-support-appcompat'
include ':skin:skin-support-cardview'
include ':skin:skin-support-constraint-layout'
include ':skin:skin-support-design'
include ':skin:mogo-skin-light'
include ':skin:mogo-skin-support-impl'
include ':skin:mogo-skin-support-noop'

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View File

@@ -40,11 +40,17 @@ dependencies {
annotationProcessor rootProject.ext.dependencies.aroutercompiler
// 换肤功能
implementation 'skin.support:skin-support:4.0.5' // skin-support
implementation 'skin.support:skin-support-appcompat:4.0.5' // skin-support 基础控件支持
implementation 'skin.support:skin-support-design:4.0.5' // skin-support-design material design 控件支持[可选]
implementation 'skin.support:skin-support-cardview:4.0.5' // skin-support-cardview CardView 控件支持[可选]
implementation 'skin.support:skin-support-constraint-layout:4.0.5' // skin-support-constraint-layout ConstraintLayout 控件支持[可选]
// implementation 'skin.support:skin-support:4.0.5' // skin-support
// implementation 'skin.support:skin-support-appcompat:4.0.5' // skin-support 基础控件支持
// implementation 'skin.support:skin-support-design:4.0.5' // skin-support-design material design 控件支持[可选]
// implementation 'skin.support:skin-support-cardview:4.0.5' // skin-support-cardview CardView 控件支持[可选]
// implementation 'skin.support:skin-support-constraint-layout:4.0.5' // skin-support-constraint-layout ConstraintLayout 控件支持[可选]
implementation project(":skin:skin-support")
implementation project(":skin:skin-support-appcompat")
implementation project(":skin:skin-support-cardview")
implementation project(":skin:skin-support-constraint-layout")
implementation project(":skin:skin-support-design")
if( Boolean.valueOf(RELEASE) ){
implementation rootProject.ext.dependencies.skinsupport

View File

@@ -0,0 +1,13 @@
package com.mogo.skin.support;
public
/**
* @author congtaowang
* @since 2020/9/2
*
* 自定义view
*/
interface IMogoSkinCompatSupportable {
void applySkin();
}

View File

@@ -0,0 +1,52 @@
package com.mogo.skin.support.helper;
import android.util.AttributeSet;
import android.view.View;
import com.mogo.skin.support.IMogoSkinCompatSupportable;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 代理 skin.support.widget.SkinCompatBackgroundHelper 类
*/
class MogoSkinCompatBackgroundHelperDelegate extends MogoSkinCompatHelperDelegate {
private static Method sMethodOnSetBackgroundResource;
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatBackgroundHelper";
}
public MogoSkinCompatBackgroundHelperDelegate( View view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{View.class};
}
public void onSetBackgroundResource( int resId ) {
if ( sMethodOnSetBackgroundResource == null ) {
try {
sMethodOnSetBackgroundResource = mTargetClazz.getDeclaredMethod( "onSetBackgroundResource", int.class );
} catch ( Exception e ) {
e.printStackTrace();
}
}
if ( sMethodOnSetBackgroundResource != null ) {
sMethodOnSetBackgroundResource.setAccessible( true );
try {
sMethodOnSetBackgroundResource.invoke( mDelegate, resId );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,54 @@
package com.mogo.skin.support.helper;
import android.view.View;
import android.widget.CompoundButton;
import com.mogo.skin.support.IMogoSkinCompatSupportable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
class MogoSkinCompatCompoundButtonHelperDelegate extends MogoSkinCompatHelperDelegate implements IMogoSkinCompatSupportable {
protected static Method sSetButtonDrawableMethod;
public MogoSkinCompatCompoundButtonHelperDelegate( CompoundButton view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{CompoundButton.class};
}
public void setButtonDrawable( int resId ) {
if ( sSetButtonDrawableMethod == null ) {
try {
sSetButtonDrawableMethod = mTargetClazz.getDeclaredMethod( "setButtonDrawable", int.class );
sSetButtonDrawableMethod.setAccessible( true );
} catch ( Exception e ) {
e.printStackTrace();
}
}
if ( sSetButtonDrawableMethod != null ) {
try {
sSetButtonDrawableMethod.invoke( mDelegate, resId );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatCompoundButtonHelper";
}
}

View File

@@ -0,0 +1,99 @@
package com.mogo.skin.support.helper;
import android.util.AttributeSet;
import android.view.View;
import com.mogo.skin.support.IMogoSkinCompatSupportable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
abstract class MogoSkinCompatHelperDelegate implements IMogoSkinCompatSupportable {
protected volatile static Class< ? > mTargetClazz;
protected Object mDelegate;
protected volatile static Method sMethodApplySkin;
protected volatile static Method sMethodLoadFromAttributes;
private static Constructor sConstructor;
public MogoSkinCompatHelperDelegate( View view ) {
loadClazz();
initDelegateInstance( view );
}
protected void loadClazz() {
if ( mTargetClazz == null ) {
try {
mTargetClazz = Class.forName( getDelegateClazzName() );
getLoadFromAttributesMethod();
getApplySkinMethod();
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
protected void initDelegateInstance( View view ) {
try {
if ( sConstructor == null ) {
if ( mTargetClazz != null ) {
sConstructor = mTargetClazz.getConstructor( getConstructParameterClazz() );
sConstructor.setAccessible( true );
}
}
if ( sConstructor != null ) {
mDelegate = sConstructor.newInstance( view );
}
} catch ( Exception e ) {
e.printStackTrace();
}
}
protected abstract Class< ? extends View >[] getConstructParameterClazz();
protected abstract String getDelegateClazzName();
protected static Method getLoadFromAttributesMethod() throws Exception {
if ( mTargetClazz != null ) {
Method method = mTargetClazz.getDeclaredMethod( "loadFromAttributes", AttributeSet.class, int.class );
method.setAccessible( true );
}
return null;
}
private static Method getApplySkinMethod() throws Exception {
if ( mTargetClazz != null ) {
Method method = mTargetClazz.getDeclaredMethod( "applySkin" );
method.setAccessible( true );
}
return null;
}
public void loadFromAttributes( AttributeSet attrs, int defStyleAttr ) {
if ( sMethodLoadFromAttributes != null ) {
try {
sMethodLoadFromAttributes.invoke( mDelegate, attrs, defStyleAttr );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
@Override
public void applySkin() {
if ( sMethodApplySkin != null ) {
try {
sMethodApplySkin.invoke( mDelegate );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,53 @@
package com.mogo.skin.support.helper;
import android.view.View;
import android.widget.ImageView;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
class MogoSkinCompatImageHelperDelegate extends MogoSkinCompatHelperDelegate {
private static Method sSetImageResourceMethod;
public MogoSkinCompatImageHelperDelegate( ImageView view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{ImageView.class};
}
public void setImageResource( int resId ) {
if ( sSetImageResourceMethod == null ) {
try {
sSetImageResourceMethod = mTargetClazz.getDeclaredMethod( "setImageResource", int.class );
sSetImageResourceMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sSetImageResourceMethod != null ) {
try {
sSetImageResourceMethod.invoke( mDelegate, resId );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatImageHelper";
}
}

View File

@@ -0,0 +1,28 @@
package com.mogo.skin.support.helper;
import android.view.View;
import android.widget.ProgressBar;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
class MogoSkinCompatProgressBarHelperDelegate extends MogoSkinCompatHelperDelegate {
public MogoSkinCompatProgressBarHelperDelegate( ProgressBar view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{ProgressBar.class};
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatProgressBarHelper";
}
}

View File

@@ -0,0 +1,28 @@
package com.mogo.skin.support.helper;
import android.view.View;
import android.widget.SeekBar;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
class MogoSkinCompatSeekBarHelperDelegate extends MogoSkinCompatHelperDelegate {
public MogoSkinCompatSeekBarHelperDelegate( SeekBar view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{SeekBar.class};
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatSeekBarHelper";
}
}

View File

@@ -0,0 +1,122 @@
package com.mogo.skin.support.helper;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
class MogoSkinCompatTextHelperDelegate extends MogoSkinCompatHelperDelegate {
private static Method sOnSetTextAppearanceMethod;
private static Method sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod;
private static Method sOnSetCompoundDrawablesWithIntrinsicBoundsMethod;
private static Method sGetTextColorResIdMethod;
public MogoSkinCompatTextHelperDelegate( TextView view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{TextView.class};
}
public void onSetTextAppearance( Context context, int resId ) {
if ( sOnSetTextAppearanceMethod == null ) {
try {
sOnSetTextAppearanceMethod = mTargetClazz.getDeclaredMethod( "onSetTextAppearance", Context.class, int.class );
sOnSetTextAppearanceMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetTextAppearanceMethod != null ) {
try {
sOnSetTextAppearanceMethod.invoke( mDelegate, context, resId );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public void onSetCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom ) {
if ( sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod == null ) {
try {
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod = mTargetClazz.getDeclaredMethod( "onSetCompoundDrawablesRelativeWithIntrinsicBounds", int.class, int.class, int.class, int.class );
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod != null ) {
try {
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod.invoke( mDelegate, start, top, end, bottom );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public void onSetCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom ) {
if ( sOnSetCompoundDrawablesWithIntrinsicBoundsMethod == null ) {
try {
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod = mTargetClazz.getDeclaredMethod( "onSetCompoundDrawablesWithIntrinsicBounds", int.class, int.class, int.class, int.class );
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetCompoundDrawablesWithIntrinsicBoundsMethod != null ) {
try {
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod.invoke( mDelegate, left, top, right, bottom );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public int getTextColorResId() {
if ( sGetTextColorResIdMethod == null ) {
try {
sGetTextColorResIdMethod = mTargetClazz.getDeclaredMethod( "getTextColorResId" );
sGetTextColorResIdMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sGetTextColorResIdMethod != null ) {
try {
Object result = sGetTextColorResIdMethod.invoke( mDelegate );
return ( ( Integer ) result ).intValue();
} catch ( Exception e ) {
e.printStackTrace();
}
}
return 0;
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatTextHelper";
}
}

View File

@@ -0,0 +1,126 @@
package com.mogo.skin.support.helper;
import android.annotation.TargetApi;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.RequiresApi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public
/**
* @author congtaowang
* @since 2020/9/3
*
* 描述
*/
@RequiresApi( 17 )
@TargetApi( 17 )
class MogoSkinCompatTextHelperV17Delegate extends MogoSkinCompatHelperDelegate {
private static Method sOnSetTextAppearanceMethod;
private static Method sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod;
private static Method sOnSetCompoundDrawablesWithIntrinsicBoundsMethod;
private static Method sGetTextColorResIdMethod;
public MogoSkinCompatTextHelperV17Delegate( TextView view ) {
super( view );
}
@Override
protected Class< ? extends View >[] getConstructParameterClazz() {
return new Class[]{TextView.class};
}
public void onSetTextAppearance( Context context, int resId ) {
if ( sOnSetTextAppearanceMethod == null ) {
try {
sOnSetTextAppearanceMethod = mTargetClazz.getDeclaredMethod( "onSetTextAppearance", Context.class, int.class );
sOnSetTextAppearanceMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetTextAppearanceMethod != null ) {
try {
sOnSetTextAppearanceMethod.invoke( mDelegate, context, resId );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public void onSetCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom ) {
if ( sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod == null ) {
try {
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod = mTargetClazz.getDeclaredMethod( "onSetCompoundDrawablesRelativeWithIntrinsicBounds", int.class, int.class, int.class, int.class );
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod != null ) {
try {
sOnSetCompoundDrawablesRelativeWithIntrinsicBoundsMethod.invoke( mDelegate, start, top, end, bottom );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public void onSetCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom ) {
if ( sOnSetCompoundDrawablesWithIntrinsicBoundsMethod == null ) {
try {
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod = mTargetClazz.getDeclaredMethod( "onSetCompoundDrawablesWithIntrinsicBounds", int.class, int.class, int.class, int.class );
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sOnSetCompoundDrawablesWithIntrinsicBoundsMethod != null ) {
try {
sOnSetCompoundDrawablesWithIntrinsicBoundsMethod.invoke( mDelegate, left, top, right, bottom );
} catch ( IllegalAccessException e ) {
e.printStackTrace();
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}
public int getTextColorResId() {
if ( sGetTextColorResIdMethod == null ) {
try {
sGetTextColorResIdMethod = mTargetClazz.getDeclaredMethod( "getTextColorResId" );
sGetTextColorResIdMethod.setAccessible( true );
} catch ( NoSuchMethodException e ) {
e.printStackTrace();
}
}
if ( sGetTextColorResIdMethod != null ) {
try {
Object result = sGetTextColorResIdMethod.invoke( mDelegate );
return ( ( Integer ) result ).intValue();
} catch ( Exception e ) {
e.printStackTrace();
}
}
return 0;
}
@Override
protected String getDelegateClazzName() {
return "skin.support.widget.SkinCompatTextHelperV17";
}
}

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MogoSkinBackgroundHelper">
<attr name="android:background" />
</declare-styleable>
<declare-styleable name="MogoSkinCompatImageView">
<attr name="android:src" />
<attr name="srcCompat" />
<attr name="android:tint" format="color" />
<attr name="tint" format="color" />
</declare-styleable>
<declare-styleable name="MogoSkinCompatTextHelper">
<attr name="android:drawableLeft" />
<attr name="android:drawableTop" />
<attr name="android:drawableRight" />
<attr name="android:drawableBottom" />
<attr name="android:drawableStart" />
<attr name="android:drawableEnd" />
<attr name="android:textAppearance" />
</declare-styleable>
<declare-styleable name="MogoSkinTextAppearance">
<attr name="android:textSize" />
<attr name="android:textColor" />
<attr name="android:textColorHint" />
<attr name="android:textStyle" />
<attr name="android:typeface" />
<attr name="textAllCaps" />
<attr name="android:shadowColor" />
<attr name="android:shadowDy" />
<attr name="android:shadowDx" />
<attr name="android:shadowRadius" />
</declare-styleable>
<declare-styleable name="SkinCompatProgressBar">
<attr name="android:indeterminateDrawable" />
<attr name="android:progressDrawable" />
</declare-styleable>
</resources>

1
skin/skin-support-appcompat/.gitignore vendored Executable file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,40 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main {
res.srcDirs = ['src/main/res', 'src/main/res-alertdialog']
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':skin:skin-support')
implementation rootProject.ext.dependencies.androidxappcompat
}
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
options.addStringOption('encoding', 'UTF-8')
options.addStringOption('charSet', 'UTF-8')
}
ext {
moduleName = 'skin-support-appcompat'
descContent = 'skin-support 基础控件换肤支持包'
}

View File

@@ -0,0 +1,21 @@
# 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

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="skin.support.appcompat" />

View File

@@ -0,0 +1,31 @@
package androidx.appcompat.app;
import android.app.Activity;
import android.content.Context;
import android.view.Window;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;
public class SkinAppCompatDelegateImpl extends AppCompatDelegateImpl {
private static Map<Activity, WeakReference<AppCompatDelegate>> sDelegateMap = new WeakHashMap<>();
public static AppCompatDelegate get(Activity activity, AppCompatCallback callback) {
WeakReference<AppCompatDelegate> delegateRef = sDelegateMap.get(activity);
AppCompatDelegate delegate = (delegateRef == null ? null : delegateRef.get());
if (delegate == null) {
delegate = new SkinAppCompatDelegateImpl(activity, activity.getWindow(), callback);
sDelegateMap.put(activity, new WeakReference<>(delegate));
}
return delegate;
}
private SkinAppCompatDelegateImpl(Context context, Window window, AppCompatCallback callback) {
super(context, window, callback);
}
@Override
public void installViewFactory() {
}
}

View File

@@ -0,0 +1,233 @@
package skin.support.app;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import androidx.core.view.ViewCompat;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.TintContextWrapper;
import androidx.appcompat.widget.VectorEnabledTintResources;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewParent;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatVectorResources;
import skin.support.utils.Slog;
import skin.support.widget.SkinCompatAutoCompleteTextView;
import skin.support.widget.SkinCompatButton;
import skin.support.widget.SkinCompatCheckBox;
import skin.support.widget.SkinCompatCheckedTextView;
import skin.support.widget.SkinCompatEditText;
import skin.support.widget.SkinCompatFrameLayout;
import skin.support.widget.SkinCompatImageButton;
import skin.support.widget.SkinCompatImageView;
import skin.support.widget.SkinCompatLinearLayout;
import skin.support.widget.SkinCompatMultiAutoCompleteTextView;
import skin.support.widget.SkinCompatProgressBar;
import skin.support.widget.SkinCompatRadioButton;
import skin.support.widget.SkinCompatRadioGroup;
import skin.support.widget.SkinCompatRatingBar;
import skin.support.widget.SkinCompatRelativeLayout;
import skin.support.widget.SkinCompatScrollView;
import skin.support.widget.SkinCompatSeekBar;
import skin.support.widget.SkinCompatSpinner;
import skin.support.widget.SkinCompatTextView;
import skin.support.widget.SkinCompatToolbar;
import skin.support.widget.SkinCompatView;
public class SkinAppCompatViewInflater implements SkinLayoutInflater, SkinWrapper {
private static final String LOG_TAG = "SkinAppCompatViewInflater";
public SkinAppCompatViewInflater() {
SkinCompatVectorResources.getInstance();
}
@Override
public View createView(Context context, String name, AttributeSet attrs) {
View view = createViewFromFV(context, name, attrs);
if (view == null) {
view = createViewFromV7(context, name, attrs);
}
return view;
}
private View createViewFromFV(Context context, String name, AttributeSet attrs) {
View view = null;
if (name.contains(".")) {
return null;
}
switch (name) {
case "View":
view = new SkinCompatView(context, attrs);
break;
case "LinearLayout":
view = new SkinCompatLinearLayout(context, attrs);
break;
case "RelativeLayout":
view = new SkinCompatRelativeLayout(context, attrs);
break;
case "FrameLayout":
view = new SkinCompatFrameLayout(context, attrs);
break;
case "TextView":
view = new SkinCompatTextView(context, attrs);
break;
case "ImageView":
view = new SkinCompatImageView(context, attrs);
break;
case "Button":
view = new SkinCompatButton(context, attrs);
break;
case "EditText":
view = new SkinCompatEditText(context, attrs);
break;
case "Spinner":
view = new SkinCompatSpinner(context, attrs);
break;
case "ImageButton":
view = new SkinCompatImageButton(context, attrs);
break;
case "CheckBox":
view = new SkinCompatCheckBox(context, attrs);
break;
case "RadioButton":
view = new SkinCompatRadioButton(context, attrs);
break;
case "RadioGroup":
view = new SkinCompatRadioGroup(context, attrs);
break;
case "CheckedTextView":
view = new SkinCompatCheckedTextView(context, attrs);
break;
case "AutoCompleteTextView":
view = new SkinCompatAutoCompleteTextView(context, attrs);
break;
case "MultiAutoCompleteTextView":
view = new SkinCompatMultiAutoCompleteTextView(context, attrs);
break;
case "RatingBar":
view = new SkinCompatRatingBar(context, attrs);
break;
case "SeekBar":
view = new SkinCompatSeekBar(context, attrs);
break;
case "ProgressBar":
view = new SkinCompatProgressBar(context, attrs);
break;
case "ScrollView":
view = new SkinCompatScrollView(context, attrs);
break;
default:
break;
}
return view;
}
private View createViewFromV7(Context context, String name, AttributeSet attrs) {
View view = null;
switch (name) {
case "androidx.appcompat.widget.Toolbar":
view = new SkinCompatToolbar(context, attrs);
break;
default:
break;
}
return view;
}
@Override
public Context wrapContext(Context context, View parent, AttributeSet attrs) {
final boolean isPre21 = Build.VERSION.SDK_INT < 21;
// We only want the View to inherit its context if we're running pre-v21
final boolean inheritContext = isPre21 && shouldInheritContext(context, (ViewParent) parent);
// We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
// by using the parent's context
if (inheritContext && parent != null) {
context = parent.getContext();
}
boolean readAndroidTheme = isPre21; /* Only read android:theme pre-L (L+ handles this anyway) */
boolean readAppTheme = true; /* Read read app:theme as a fallback at all times for legacy reasons */
boolean wrapContext = VectorEnabledTintResources.shouldBeUsed(); /* Only tint wrap the context if enabled */
// We can emulate Lollipop's android:theme attribute propagating down the view hierarchy
// by using the parent's context
if (inheritContext && parent != null) {
context = parent.getContext();
}
if (readAndroidTheme || readAppTheme) {
// We then apply the theme on the context, if specified
context = themifyContext(context, attrs, readAndroidTheme, readAppTheme);
}
if (wrapContext) {
context = TintContextWrapper.wrap(context);
}
return context;
}
private boolean shouldInheritContext(Context context, ViewParent parent) {
if (parent == null) {
// The initial parent is null so just return false
return false;
}
if (context instanceof Activity) {
final View windowDecor = ((Activity) context).getWindow().getDecorView();
while (true) {
if (parent == null) {
// Bingo. We've hit a view which has a null parent before being terminated from
// the loop. This is (most probably) because it's the root view in an inflation
// call, therefore we should inherit. This works as the inflated layout is only
// added to the hierarchy at the end of the inflate() call.
return true;
} else if (parent == windowDecor || !(parent instanceof View)
|| ViewCompat.isAttachedToWindow((View) parent)) {
// We have either hit the window's decor view, a parent which isn't a View
// (i.e. ViewRootImpl), or an attached view, so we know that the original parent
// is currently added to the view hierarchy. This means that it has not be
// inflated in the current inflate() call and we should not inherit the context.
return false;
}
parent = parent.getParent();
}
}
return false;
}
/**
* Allows us to emulate the {@code android:theme} attribute for devices before L.
*/
private static Context themifyContext(Context context, AttributeSet attrs,
boolean useAndroidTheme, boolean useAppTheme) {
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.View, 0, 0);
int themeId = 0;
if (useAndroidTheme) {
// First try reading android:theme if enabled
themeId = a.getResourceId(R.styleable.View_android_theme, 0);
}
if (useAppTheme && themeId == 0) {
// ...if that didn't work, try reading app:theme (for legacy reasons) if enabled
themeId = a.getResourceId(R.styleable.View_theme, 0);
if (themeId != 0) {
Slog.i(LOG_TAG, "app:theme is now deprecated. "
+ "Please move to using android:theme instead.");
}
}
a.recycle();
if (themeId != 0 && (!(context instanceof ContextThemeWrapper)
|| ((ContextThemeWrapper) context).getThemeResId() != themeId)) {
// If the context isn't a ContextThemeWrapper, or it is but does not have
// the same theme as we need, wrap it in a new wrapper
context = new ContextThemeWrapper(context, themeId);
}
return context;
}
}

View File

@@ -0,0 +1,74 @@
package skin.support.app;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.LayoutInflaterCompat;
import androidx.appcompat.app.AppCompatActivity;
import skin.support.SkinCompatManager;
import skin.support.content.res.SkinCompatThemeUtils;
import skin.support.content.res.SkinCompatVectorResources;
import skin.support.observe.SkinObservable;
import skin.support.observe.SkinObserver;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
import static skin.support.widget.SkinCompatHelper.checkResourceId;
/**
* Created by ximsfei on 17-1-8.
*/
@Deprecated
public class SkinCompatActivity extends AppCompatActivity implements SkinObserver {
private SkinCompatDelegate mSkinDelegate;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
LayoutInflaterCompat.setFactory2(getLayoutInflater(), getSkinDelegate());
super.onCreate(savedInstanceState);
updateStatusBarColor();
updateWindowBackground();
}
@NonNull
public SkinCompatDelegate getSkinDelegate() {
if (mSkinDelegate == null) {
mSkinDelegate = SkinCompatDelegate.create(this);
}
return mSkinDelegate;
}
@Override
protected void onResume() {
super.onResume();
SkinCompatManager.getInstance().addObserver(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
SkinCompatManager.getInstance().deleteObserver(this);
}
protected void updateStatusBarColor() {
}
protected void updateWindowBackground() {
int windowBackgroundResId = SkinCompatThemeUtils.getWindowBackgroundResId(this);
if (checkResourceId(windowBackgroundResId) != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(this, windowBackgroundResId);
if (drawable != null) {
getWindow().setBackgroundDrawable(drawable);
}
}
}
@Override
public void updateSkin(SkinObservable observable, Object o) {
updateStatusBarColor();
updateWindowBackground();
getSkinDelegate().applySkin();
}
}

View File

@@ -0,0 +1,754 @@
package skin.support.content.res;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable.ConstantState;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.collection.ArrayMap;
import androidx.collection.LongSparseArray;
import androidx.collection.LruCache;
import androidx.appcompat.R;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import static androidx.core.graphics.ColorUtils.compositeColors;
import static skin.support.content.res.SkinCompatThemeUtils.getDisabledThemeAttrColor;
import static skin.support.content.res.SkinCompatThemeUtils.getThemeAttrColor;
import static skin.support.content.res.SkinCompatThemeUtils.getThemeAttrColorStateList;
final class SkinCompatDrawableManager {
private interface InflateDelegate {
Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Resources.Theme theme);
}
private static final String TAG = SkinCompatDrawableManager.class.getSimpleName();
private static final boolean DEBUG = false;
private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;
private static final String SKIP_DRAWABLE_TAG = "appcompat_skip_skip";
private static final String PLATFORM_VD_CLAZZ = "android.graphics.drawable.VectorDrawable";
private static SkinCompatDrawableManager INSTANCE;
public static SkinCompatDrawableManager get() {
if (INSTANCE == null) {
INSTANCE = new SkinCompatDrawableManager();
installDefaultInflateDelegates(INSTANCE);
}
return INSTANCE;
}
private static void installDefaultInflateDelegates(@NonNull SkinCompatDrawableManager manager) {
// This sdk version check will affect src:appCompat code path.
// Although VectorDrawable exists in Android framework from Lollipop, AppCompat will use the
// VectorDrawableCompat before Nougat to utilize the bug fixes in VectorDrawableCompat.
if (Build.VERSION.SDK_INT < 24) {
manager.addDelegate("vector", new VdcInflateDelegate());
// AnimatedVectorDrawableCompat only works on API v11+
manager.addDelegate("animated-vector", new AvdcInflateDelegate());
}
}
private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6);
/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlNormal},
* using the default mode using a raw color filter.
*/
private static final int[] COLORFILTER_TINT_COLOR_CONTROL_NORMAL = {
R.drawable.abc_textfield_search_default_mtrl_alpha,
R.drawable.abc_textfield_default_mtrl_alpha,
R.drawable.abc_ab_share_pack_mtrl_alpha
};
/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, using
* {@link DrawableCompat}'s tinting functionality.
*/
private static final int[] TINT_COLOR_CONTROL_NORMAL = {
R.drawable.abc_ic_commit_search_api_mtrl_alpha,
R.drawable.abc_seekbar_tick_mark_material,
R.drawable.abc_ic_menu_share_mtrl_alpha,
R.drawable.abc_ic_menu_copy_mtrl_am_alpha,
R.drawable.abc_ic_menu_cut_mtrl_alpha,
R.drawable.abc_ic_menu_selectall_mtrl_alpha,
R.drawable.abc_ic_menu_paste_mtrl_am_alpha
};
/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlActivated},
* using a color filter.
*/
private static final int[] COLORFILTER_COLOR_CONTROL_ACTIVATED = {
R.drawable.abc_textfield_activated_mtrl_alpha,
R.drawable.abc_textfield_search_activated_mtrl_alpha,
R.drawable.abc_cab_background_top_mtrl_alpha,
R.drawable.abc_text_cursor_material,
R.drawable.abc_text_select_handle_left_mtrl_dark,
R.drawable.abc_text_select_handle_middle_mtrl_dark,
R.drawable.abc_text_select_handle_right_mtrl_dark,
R.drawable.abc_text_select_handle_left_mtrl_light,
R.drawable.abc_text_select_handle_middle_mtrl_light,
R.drawable.abc_text_select_handle_right_mtrl_light
};
/**
* Drawables which should be tinted with the value of {@code android.R.attr.colorBackground},
* using the {@link PorterDuff.Mode#MULTIPLY} mode and a color filter.
*/
private static final int[] COLORFILTER_COLOR_BACKGROUND_MULTIPLY = {
R.drawable.abc_popup_background_mtrl_mult,
R.drawable.abc_cab_background_internal_bg,
R.drawable.abc_menu_hardkey_panel_mtrl_mult
};
/**
* Drawables which should be tinted using a state list containing values of
* {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
*/
private static final int[] TINT_COLOR_CONTROL_STATE_LIST = {
R.drawable.abc_tab_indicator_material,
R.drawable.abc_textfield_search_material
};
/**
* Drawables which should be tinted using a state list containing values of
* {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated} for the checked
* state.
*/
private static final int[] TINT_CHECKABLE_BUTTON_LIST = {
R.drawable.abc_btn_check_material,
R.drawable.abc_btn_radio_material
};
private WeakHashMap<Context, SparseArray<ColorStateList>> mTintLists;
private ArrayMap<String, InflateDelegate> mDelegates;
private SparseArray<String> mKnownDrawableIdTags;
private final Object mDrawableCacheLock = new Object();
private final WeakHashMap<Context, LongSparseArray<WeakReference<ConstantState>>>
mDrawableCaches = new WeakHashMap<>(0);
private TypedValue mTypedValue;
private boolean mHasCheckedVectorDrawableSetup;
void clearCaches() {
mDrawableCaches.clear();
if (mKnownDrawableIdTags != null) {
mKnownDrawableIdTags.clear();
}
if (mTintLists != null) {
mTintLists.clear();
}
COLOR_FILTER_CACHE.evictAll();
}
public Drawable getDrawable(@NonNull Context context, @DrawableRes int resId) {
return getDrawable(context, resId, false);
}
Drawable getDrawable(@NonNull Context context, @DrawableRes int resId,
boolean failIfNotKnown) {
checkVectorDrawableSetup(context);
Drawable drawable = loadDrawableFromDelegates(context, resId);
if (drawable == null) {
drawable = createDrawableIfNeeded(context, resId);
}
if (drawable == null) {
drawable = SkinCompatResources.getDrawable(context, resId);
}
if (drawable != null) {
// Tint it if needed
drawable = tintDrawable(context, resId, failIfNotKnown, drawable);
}
if (drawable != null) {
// See if we need to 'fix' the drawable
SkinCompatDrawableUtils.fixDrawable(drawable);
}
return drawable;
}
public void onConfigurationChanged(@NonNull Context context) {
synchronized (mDrawableCacheLock) {
LongSparseArray<WeakReference<ConstantState>> cache = mDrawableCaches.get(context);
if (cache != null) {
// Crude, but we'll just clear the cache when the configuration changes
cache.clear();
}
}
}
private static long createCacheKey(TypedValue tv) {
return (((long) tv.assetCookie) << 32) | tv.data;
}
private Drawable createDrawableIfNeeded(@NonNull Context context,
@DrawableRes final int resId) {
if (mTypedValue == null) {
mTypedValue = new TypedValue();
}
final TypedValue tv = mTypedValue;
SkinCompatResources.getValue(context, resId, tv, true);
final long key = createCacheKey(tv);
Drawable dr = getCachedDrawable(context, key);
if (dr != null) {
// If we got a cached drawable, return it
return dr;
}
// Else we need to try and create one...
if (resId == R.drawable.abc_cab_background_top_material) {
dr = new LayerDrawable(new Drawable[]{
getDrawable(context, R.drawable.abc_cab_background_internal_bg),
getDrawable(context, R.drawable.abc_cab_background_top_mtrl_alpha)
});
}
if (dr != null) {
dr.setChangingConfigurations(tv.changingConfigurations);
// If we reached here then we created a new drawable, add it to the cache
addDrawableToCache(context, key, dr);
}
return dr;
}
private Drawable tintDrawable(@NonNull Context context, @DrawableRes int resId,
boolean failIfNotKnown, @NonNull Drawable drawable) {
final ColorStateList tintList = getTintList(context, resId);
if (tintList != null) {
// First mutate the Drawable, then wrap it and set the tint list
if (SkinCompatDrawableUtils.canSafelyMutateDrawable(drawable)) {
drawable = drawable.mutate();
}
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTintList(drawable, tintList);
// If there is a blending mode specified for the drawable, use it
final PorterDuff.Mode tintMode = getTintMode(resId);
if (tintMode != null) {
DrawableCompat.setTintMode(drawable, tintMode);
}
} else if (resId == R.drawable.abc_seekbar_track_material) {
LayerDrawable ld = (LayerDrawable) drawable;
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.background),
getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.secondaryProgress),
getThemeAttrColor(context, R.attr.colorControlNormal), DEFAULT_MODE);
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.progress),
getThemeAttrColor(context, R.attr.colorControlActivated), DEFAULT_MODE);
} else if (resId == R.drawable.abc_ratingbar_material
|| resId == R.drawable.abc_ratingbar_indicator_material
|| resId == R.drawable.abc_ratingbar_small_material) {
LayerDrawable ld = (LayerDrawable) drawable;
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.background),
getDisabledThemeAttrColor(context, R.attr.colorControlNormal),
DEFAULT_MODE);
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.secondaryProgress),
getThemeAttrColor(context, R.attr.colorControlActivated), DEFAULT_MODE);
setPorterDuffColorFilter(ld.findDrawableByLayerId(android.R.id.progress),
getThemeAttrColor(context, R.attr.colorControlActivated), DEFAULT_MODE);
} else {
final boolean tinted = tintDrawableUsingColorFilter(context, resId, drawable);
if (!tinted && failIfNotKnown) {
// If we didn't tint using a ColorFilter, and we're set to fail if we don't
// know the id, return null
drawable = null;
}
}
return drawable;
}
private Drawable loadDrawableFromDelegates(@NonNull Context context, @DrawableRes int resId) {
if (mDelegates != null && !mDelegates.isEmpty()) {
if (mKnownDrawableIdTags != null) {
final String cachedTagName = mKnownDrawableIdTags.get(resId);
if (SKIP_DRAWABLE_TAG.equals(cachedTagName)
|| (cachedTagName != null && mDelegates.get(cachedTagName) == null)) {
// If we don't have a delegate for the drawable tag, or we've been set to
// skip it, fail fast and return null
if (DEBUG) {
Log.d(TAG, "[loadDrawableFromDelegates] Skipping drawable: "
+ context.getResources().getResourceName(resId));
}
return null;
}
} else {
// Create an id cache as we'll need one later
mKnownDrawableIdTags = new SparseArray<>();
}
if (mTypedValue == null) {
mTypedValue = new TypedValue();
}
final TypedValue tv = mTypedValue;
SkinCompatResources.getValue(context, resId, tv, true);
final long key = createCacheKey(tv);
Drawable dr = getCachedDrawable(context, key);
if (dr != null) {
if (DEBUG) {
Log.i(TAG, "[loadDrawableFromDelegates] Returning cached drawable: " +
context.getResources().getResourceName(resId));
}
// We have a cached drawable, return it!
return dr;
}
if (tv.string != null && tv.string.toString().endsWith(".xml")) {
// If the resource is an XML file, let's try and parse it
try {
final XmlPullParser parser = SkinCompatResources.getXml(context, resId);
final AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG &&
type != XmlPullParser.END_DOCUMENT) {
// Empty loop
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException("No start tag found");
}
final String tagName = parser.getName();
// Add the tag name to the cache
mKnownDrawableIdTags.append(resId, tagName);
// Now try and find a delegate for the tag name and inflate if found
final InflateDelegate delegate = mDelegates.get(tagName);
if (delegate != null) {
dr = delegate.createFromXmlInner(context, parser, attrs, null);
}
if (dr != null) {
// Add it to the drawable cache
dr.setChangingConfigurations(tv.changingConfigurations);
if (addDrawableToCache(context, key, dr) && DEBUG) {
Log.i(TAG, "[loadDrawableFromDelegates] Saved drawable to cache: " +
context.getResources().getResourceName(resId));
}
}
} catch (Exception e) {
Log.e(TAG, "Exception while inflating drawable", e);
}
}
if (dr == null) {
// If we reach here then the delegate inflation of the resource failed. Mark it as
// bad so we skip the id next time
mKnownDrawableIdTags.append(resId, SKIP_DRAWABLE_TAG);
}
return dr;
}
return null;
}
private Drawable getCachedDrawable(@NonNull final Context context, final long key) {
synchronized (mDrawableCacheLock) {
final LongSparseArray<WeakReference<ConstantState>> cache
= mDrawableCaches.get(context);
if (cache == null) {
return null;
}
final WeakReference<ConstantState> wr = cache.get(key);
if (wr != null) {
// We have the key, and the secret
ConstantState entry = wr.get();
if (entry != null) {
return entry.newDrawable(context.getResources());
} else {
// Our entry has been purged
cache.delete(key);
}
}
}
return null;
}
private boolean addDrawableToCache(@NonNull final Context context, final long key,
@NonNull final Drawable drawable) {
final ConstantState cs = drawable.getConstantState();
if (cs != null) {
synchronized (mDrawableCacheLock) {
LongSparseArray<WeakReference<ConstantState>> cache = mDrawableCaches.get(context);
if (cache == null) {
cache = new LongSparseArray<>();
mDrawableCaches.put(context, cache);
}
cache.put(key, new WeakReference<ConstantState>(cs));
}
return true;
}
return false;
}
static boolean tintDrawableUsingColorFilter(@NonNull Context context,
@DrawableRes final int resId, @NonNull Drawable drawable) {
PorterDuff.Mode tintMode = DEFAULT_MODE;
boolean colorAttrSet = false;
int colorAttr = 0;
int alpha = -1;
if (arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, resId)) {
colorAttr = R.attr.colorControlNormal;
colorAttrSet = true;
} else if (arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, resId)) {
colorAttr = R.attr.colorControlActivated;
colorAttrSet = true;
} else if (arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, resId)) {
colorAttr = android.R.attr.colorBackground;
colorAttrSet = true;
tintMode = PorterDuff.Mode.MULTIPLY;
} else if (resId == R.drawable.abc_list_divider_mtrl_alpha) {
colorAttr = android.R.attr.colorForeground;
colorAttrSet = true;
alpha = Math.round(0.16f * 255);
} else if (resId == R.drawable.abc_dialog_material_background) {
colorAttr = android.R.attr.colorBackground;
colorAttrSet = true;
}
if (colorAttrSet) {
if (SkinCompatDrawableUtils.canSafelyMutateDrawable(drawable)) {
drawable = drawable.mutate();
}
final int color = getThemeAttrColor(context, colorAttr);
drawable.setColorFilter(getPorterDuffColorFilter(color, tintMode));
if (alpha != -1) {
drawable.setAlpha(alpha);
}
if (DEBUG) {
Log.d(TAG, "[tintDrawableUsingColorFilter] Tinted "
+ context.getResources().getResourceName(resId) +
" with color: #" + Integer.toHexString(color));
}
return true;
}
return false;
}
private void addDelegate(@NonNull String tagName, @NonNull InflateDelegate delegate) {
if (mDelegates == null) {
mDelegates = new ArrayMap<>();
}
mDelegates.put(tagName, delegate);
}
private void removeDelegate(@NonNull String tagName, @NonNull InflateDelegate delegate) {
if (mDelegates != null && mDelegates.get(tagName) == delegate) {
mDelegates.remove(tagName);
}
}
private static boolean arrayContains(int[] array, int value) {
for (int id : array) {
if (id == value) {
return true;
}
}
return false;
}
static PorterDuff.Mode getTintMode(final int resId) {
PorterDuff.Mode mode = null;
if (resId == R.drawable.abc_switch_thumb_material) {
mode = PorterDuff.Mode.MULTIPLY;
}
return mode;
}
ColorStateList getTintList(@NonNull Context context, @DrawableRes int resId) {
// Try the cache first (if it exists)
ColorStateList tint = getTintListFromCache(context, resId);
if (tint == null) {
// ...if the cache did not contain a color state list, try and create one
if (resId == R.drawable.abc_edit_text_material) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_edittext);
} else if (resId == R.drawable.abc_switch_track_mtrl_alpha) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_switch_track);
} else if (resId == R.drawable.abc_switch_thumb_material) {
tint = createSwitchThumbColorStateList(context);
} else if (resId == R.drawable.abc_btn_default_mtrl_shape) {
tint = createDefaultButtonColorStateList(context);
} else if (resId == R.drawable.abc_btn_borderless_material) {
tint = createBorderlessButtonColorStateList(context);
} else if (resId == R.drawable.abc_btn_colored_material) {
tint = createColoredButtonColorStateList(context);
} else if (resId == R.drawable.abc_spinner_mtrl_am_alpha
|| resId == R.drawable.abc_spinner_textfield_background_material) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_spinner);
} else if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
tint = getThemeAttrColorStateList(context, R.attr.colorControlNormal);
} else if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_default);
} else if (arrayContains(TINT_CHECKABLE_BUTTON_LIST, resId)) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_btn_checkable);
} else if (resId == R.drawable.abc_seekbar_thumb_material) {
tint = SkinCompatResources.getColorStateList(context, R.color.abc_tint_seek_thumb);
}
if (tint != null) {
addTintListToCache(context, resId, tint);
}
}
return tint;
}
private ColorStateList getTintListFromCache(@NonNull Context context, @DrawableRes int resId) {
if (mTintLists != null) {
final SparseArray<ColorStateList> tints = mTintLists.get(context);
return tints != null ? tints.get(resId) : null;
}
return null;
}
private void addTintListToCache(@NonNull Context context, @DrawableRes int resId,
@NonNull ColorStateList tintList) {
if (mTintLists == null) {
mTintLists = new WeakHashMap<>();
}
SparseArray<ColorStateList> themeTints = mTintLists.get(context);
if (themeTints == null) {
themeTints = new SparseArray<>();
mTintLists.put(context, themeTints);
}
themeTints.append(resId, tintList);
}
private ColorStateList createDefaultButtonColorStateList(@NonNull Context context) {
return createButtonColorStateList(context,
getThemeAttrColor(context, R.attr.colorButtonNormal));
}
private ColorStateList createBorderlessButtonColorStateList(@NonNull Context context) {
// We ignore the custom tint for borderless buttons
return createButtonColorStateList(context, Color.TRANSPARENT);
}
private ColorStateList createColoredButtonColorStateList(@NonNull Context context) {
return createButtonColorStateList(context,
getThemeAttrColor(context, R.attr.colorAccent));
}
private ColorStateList createButtonColorStateList(@NonNull final Context context,
@ColorInt final int baseColor) {
final int[][] states = new int[4][];
final int[] colors = new int[4];
int i = 0;
final int colorControlHighlight = getThemeAttrColor(context, R.attr.colorControlHighlight);
final int disabledColor = getDisabledThemeAttrColor(context, R.attr.colorButtonNormal);
// Disabled state
states[i] = SkinCompatThemeUtils.DISABLED_STATE_SET;
colors[i] = disabledColor;
i++;
states[i] = SkinCompatThemeUtils.PRESSED_STATE_SET;
colors[i] = compositeColors(colorControlHighlight, baseColor);
i++;
states[i] = SkinCompatThemeUtils.FOCUSED_STATE_SET;
colors[i] = compositeColors(colorControlHighlight, baseColor);
i++;
// Default enabled state
states[i] = SkinCompatThemeUtils.EMPTY_STATE_SET;
colors[i] = baseColor;
i++;
return new ColorStateList(states, colors);
}
private ColorStateList createSwitchThumbColorStateList(Context context) {
final int[][] states = new int[3][];
final int[] colors = new int[3];
int i = 0;
final ColorStateList thumbColor = SkinCompatThemeUtils.getThemeAttrColorStateList(context,
R.attr.colorSwitchThumbNormal);
if (thumbColor != null && thumbColor.isStateful()) {
// If colorSwitchThumbNormal is a valid ColorStateList, extract the default and
// disabled colors from it
// Disabled state
states[i] = SkinCompatThemeUtils.DISABLED_STATE_SET;
colors[i] = thumbColor.getColorForState(states[i], 0);
i++;
states[i] = SkinCompatThemeUtils.CHECKED_STATE_SET;
colors[i] = SkinCompatThemeUtils.getThemeAttrColor(context, R.attr.colorControlActivated);
i++;
// Default enabled state
states[i] = SkinCompatThemeUtils.EMPTY_STATE_SET;
colors[i] = thumbColor.getDefaultColor();
i++;
} else {
// Else we'll use an approximation using the default disabled alpha
// Disabled state
states[i] = SkinCompatThemeUtils.DISABLED_STATE_SET;
colors[i] = SkinCompatThemeUtils.getDisabledThemeAttrColor(context, R.attr.colorSwitchThumbNormal);
i++;
states[i] = SkinCompatThemeUtils.CHECKED_STATE_SET;
colors[i] = SkinCompatThemeUtils.getThemeAttrColor(context, R.attr.colorControlActivated);
i++;
// Default enabled state
states[i] = SkinCompatThemeUtils.EMPTY_STATE_SET;
colors[i] = SkinCompatThemeUtils.getThemeAttrColor(context, R.attr.colorSwitchThumbNormal);
i++;
}
return new ColorStateList(states, colors);
}
private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
public ColorFilterLruCache(int maxSize) {
super(maxSize);
}
PorterDuffColorFilter get(int color, PorterDuff.Mode mode) {
return get(generateCacheKey(color, mode));
}
PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) {
return put(generateCacheKey(color, mode), filter);
}
private static int generateCacheKey(int color, PorterDuff.Mode mode) {
int hashCode = 1;
hashCode = 31 * hashCode + color;
hashCode = 31 * hashCode + mode.hashCode();
return hashCode;
}
}
private static PorterDuffColorFilter createTintFilter(ColorStateList tint,
PorterDuff.Mode tintMode, final int[] state) {
if (tint == null || tintMode == null) {
return null;
}
final int color = tint.getColorForState(state, Color.TRANSPARENT);
return getPorterDuffColorFilter(color, tintMode);
}
public static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) {
// First, lets see if the cache already contains the color filter
PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
if (filter == null) {
// Cache miss, so create a color filter and add it to the cache
filter = new PorterDuffColorFilter(color, mode);
COLOR_FILTER_CACHE.put(color, mode, filter);
}
return filter;
}
private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) {
if (SkinCompatDrawableUtils.canSafelyMutateDrawable(d)) {
d = d.mutate();
}
d.setColorFilter(getPorterDuffColorFilter(color, mode == null ? DEFAULT_MODE : mode));
}
private void checkVectorDrawableSetup(@NonNull Context context) {
if (mHasCheckedVectorDrawableSetup) {
// We've already checked so return now...
return;
}
// Here we will check that a known Vector drawable resource inside AppCompat can be
// correctly decoded
mHasCheckedVectorDrawableSetup = true;
final Drawable d = getDrawable(context, R.drawable.abc_vector_test);
if (d == null || !isVectorDrawable(d)) {
mHasCheckedVectorDrawableSetup = false;
throw new IllegalStateException("This app has been built with an incorrect "
+ "configuration. Please configure your build for VectorDrawableCompat.");
}
}
private static boolean isVectorDrawable(@NonNull Drawable d) {
return d instanceof VectorDrawableCompat
|| PLATFORM_VD_CLAZZ.equals(d.getClass().getName());
}
private static class VdcInflateDelegate implements InflateDelegate {
VdcInflateDelegate() {
}
@SuppressLint("NewApi")
@Override
public Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Resources.Theme theme) {
try {
return VectorDrawableCompat
.createFromXmlInner(context.getResources(), parser, attrs, theme);
} catch (Exception e) {
Log.e("VdcInflateDelegate", "Exception while inflating <vector>", e);
return null;
}
}
}
@RequiresApi(11)
@TargetApi(11)
private static class AvdcInflateDelegate implements InflateDelegate {
AvdcInflateDelegate() {
}
@SuppressLint("NewApi")
@Override
public Drawable createFromXmlInner(@NonNull Context context, @NonNull XmlPullParser parser,
@NonNull AttributeSet attrs, @Nullable Resources.Theme theme) {
try {
return AnimatedVectorDrawableCompat
.createFromXmlInner(context, context.getResources(), parser, attrs, theme);
} catch (Exception e) {
Log.e("AvdcInflateDelegate", "Exception while inflating <animated-vector>", e);
return null;
}
}
}
}

View File

@@ -0,0 +1,90 @@
package skin.support.content.res;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableContainer;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ScaleDrawable;
import android.os.Build;
import androidx.annotation.NonNull;
import skin.support.utils.SkinCompatVersionUtils;
class SkinCompatDrawableUtils {
private static final String VECTOR_DRAWABLE_CLAZZ_NAME
= "android.graphics.drawable.VectorDrawable";
/**
* Attempt the fix any issues in the given drawable, usually caused by platform bugs in the
* implementation. This method should be call after retrieval from
* {@link android.content.res.Resources} or a {@link android.content.res.TypedArray}.
*/
static void fixDrawable(@NonNull final Drawable drawable) {
if (Build.VERSION.SDK_INT == 21
&& VECTOR_DRAWABLE_CLAZZ_NAME.equals(drawable.getClass().getName())) {
fixVectorDrawableTinting(drawable);
}
}
/**
* Some drawable implementations have problems with mutation. This method returns false if
* there is a known issue in the given drawable's implementation.
*/
public static boolean canSafelyMutateDrawable(@NonNull Drawable drawable) {
if (Build.VERSION.SDK_INT < 15 && drawable instanceof InsetDrawable) {
return false;
} else if (Build.VERSION.SDK_INT < 15 && drawable instanceof GradientDrawable) {
// GradientDrawable has a bug pre-ICS which results in mutate() resulting
// in loss of color
return false;
} else if (Build.VERSION.SDK_INT < 17 && drawable instanceof LayerDrawable) {
return false;
}
if (drawable instanceof DrawableContainer) {
// If we have a DrawableContainer, let's traverse it's child array
final Drawable.ConstantState state = drawable.getConstantState();
if (state instanceof DrawableContainer.DrawableContainerState) {
final DrawableContainer.DrawableContainerState containerState =
(DrawableContainer.DrawableContainerState) state;
for (final Drawable child : containerState.getChildren()) {
if (!canSafelyMutateDrawable(child)) {
return false;
}
}
}
} else if (SkinCompatVersionUtils.isV4DrawableWrapper(drawable)) {
return canSafelyMutateDrawable(SkinCompatVersionUtils.getV4DrawableWrapperWrappedDrawable(drawable));
} else if (SkinCompatVersionUtils.isV4WrappedDrawable(drawable)) {
return canSafelyMutateDrawable(SkinCompatVersionUtils.getV4WrappedDrawableWrappedDrawable(drawable));
} else if (SkinCompatVersionUtils.isV7DrawableWrapper(drawable)) {
return canSafelyMutateDrawable(SkinCompatVersionUtils.getV7DrawableWrapperWrappedDrawable(drawable));
} else if (drawable instanceof ScaleDrawable) {
Drawable scaleDrawable = ((ScaleDrawable) drawable).getDrawable();
if (scaleDrawable != null) {
return canSafelyMutateDrawable(scaleDrawable);
}
}
return true;
}
/**
* VectorDrawable has an issue on API 21 where it sometimes doesn't create its tint filter.
* Fixed by toggling it's state to force a filter creation.
*/
private static void fixVectorDrawableTinting(final Drawable drawable) {
final int[] originalState = drawable.getState();
if (originalState == null || originalState.length == 0) {
// The drawable doesn't have a state, so set it to be checked
drawable.setState(SkinCompatThemeUtils.CHECKED_STATE_SET);
} else {
// Else the drawable does have a state, so clear it
drawable.setState(SkinCompatThemeUtils.EMPTY_STATE_SET);
}
// Now set the original state
drawable.setState(originalState);
}
}

View File

@@ -0,0 +1,34 @@
package skin.support.content.res;
import android.content.Context;
import static skin.support.content.res.SkinCompatThemeUtils.getResId;
/**
* Created by ximsfei on 2017/3/25.
*/
public class SkinCompatV7ThemeUtils {
private static final int[] APPCOMPAT_COLOR_PRIMARY_ATTRS = {
androidx.appcompat.R.attr.colorPrimary
};
private static final int[] APPCOMPAT_COLOR_PRIMARY_DARK_ATTRS = {
androidx.appcompat.R.attr.colorPrimaryDark
};
private static final int[] APPCOMPAT_COLOR_ACCENT_ATTRS = {
androidx.appcompat.R.attr.colorAccent
};
public static int getColorPrimaryResId(Context context) {
return getResId(context, APPCOMPAT_COLOR_PRIMARY_ATTRS);
}
public static int getColorPrimaryDarkResId(Context context) {
return getResId(context, APPCOMPAT_COLOR_PRIMARY_DARK_ATTRS);
}
public static int getColorAccentResId(Context context) {
return getResId(context, APPCOMPAT_COLOR_ACCENT_ATTRS);
}
}

View File

@@ -0,0 +1,91 @@
package skin.support.content.res;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.content.res.AppCompatResources;
public class SkinCompatVectorResources implements SkinResources {
private static SkinCompatVectorResources sInstance;
private SkinCompatVectorResources() {
SkinCompatResources.getInstance().addSkinResources(this);
}
public static SkinCompatVectorResources getInstance() {
if (sInstance == null) {
synchronized (SkinCompatVectorResources.class) {
if (sInstance == null) {
sInstance = new SkinCompatVectorResources();
}
}
}
return sInstance;
}
@Override
public void clear() {
SkinCompatDrawableManager.get().clearCaches();
}
private Drawable getSkinDrawableCompat(Context context, int resId) {
if (AppCompatDelegate.isCompatVectorFromResourcesEnabled()) {
if (!SkinCompatResources.getInstance().isDefaultSkin()) {
try {
return SkinCompatDrawableManager.get().getDrawable(context, resId);
} catch (Exception e) {
e.printStackTrace();
}
}
// SkinCompatDrawableManager.get().getDrawable(context, resId) 中会调用getSkinDrawable等方法。
// 这里只需要拦截使用默认皮肤的情况。
if (!SkinCompatUserThemeManager.get().isColorEmpty()) {
ColorStateList colorStateList = SkinCompatUserThemeManager.get().getColorStateList(resId);
if (colorStateList != null) {
return new ColorDrawable(colorStateList.getDefaultColor());
}
}
if (!SkinCompatUserThemeManager.get().isDrawableEmpty()) {
Drawable drawable = SkinCompatUserThemeManager.get().getDrawable(resId);
if (drawable != null) {
return drawable;
}
}
Drawable drawable = SkinCompatResources.getInstance().getStrategyDrawable(context, resId);
if (drawable != null) {
return drawable;
}
return AppCompatResources.getDrawable(context, resId);
} else {
if (!SkinCompatUserThemeManager.get().isColorEmpty()) {
ColorStateList colorStateList = SkinCompatUserThemeManager.get().getColorStateList(resId);
if (colorStateList != null) {
return new ColorDrawable(colorStateList.getDefaultColor());
}
}
if (!SkinCompatUserThemeManager.get().isDrawableEmpty()) {
Drawable drawable = SkinCompatUserThemeManager.get().getDrawable(resId);
if (drawable != null) {
return drawable;
}
}
Drawable drawable = SkinCompatResources.getInstance().getStrategyDrawable(context, resId);
if (drawable != null) {
return drawable;
}
if (!SkinCompatResources.getInstance().isDefaultSkin()) {
int targetResId = SkinCompatResources.getInstance().getTargetResId(context, resId);
if (targetResId != 0) {
return SkinCompatResources.getInstance().getSkinResources().getDrawable(targetResId);
}
}
return AppCompatResources.getDrawable(context, resId);
}
}
public static Drawable getDrawableCompat(Context context, int resId) {
return getInstance().getSkinDrawableCompat(context, resId);
}
}

View File

@@ -0,0 +1,116 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
import android.util.AttributeSet;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatVectorResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 2017/1/13.
*/
public class SkinCompatAutoCompleteTextView extends AppCompatAutoCompleteTextView implements SkinCompatSupportable {
private static final int[] TINT_ATTRS = {
android.R.attr.popupBackground
};
private int mDropDownBackgroundResId = INVALID_ID;
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatAutoCompleteTextView(Context context) {
this(context, null);
}
public SkinCompatAutoCompleteTextView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.autoCompleteTextViewStyle);
}
public SkinCompatAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, TINT_ATTRS, defStyleAttr, 0);
if (a.hasValue(0)) {
mDropDownBackgroundResId = a.getResourceId(0, INVALID_ID);
}
a.recycle();
applyDropDownBackgroundResource();
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setDropDownBackgroundResource(@DrawableRes int resId) {
super.setDropDownBackgroundResource(resId);
mDropDownBackgroundResId = resId;
applyDropDownBackgroundResource();
}
private void applyDropDownBackgroundResource() {
mDropDownBackgroundResId = SkinCompatHelper.checkResourceId(mDropDownBackgroundResId);
if (mDropDownBackgroundResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(getContext(), mDropDownBackgroundResId);
if (drawable != null) {
setDropDownBackgroundDrawable(drawable);
}
}
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
applyDropDownBackgroundResource();
}
}

View File

@@ -0,0 +1,60 @@
package skin.support.widget;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.view.View;
import skin.support.R;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by ximsfei on 2017/1/10.
*/
public class SkinCompatBackgroundHelper extends SkinCompatHelper {
private final View mView;
private int mBackgroundResId = INVALID_ID;
public SkinCompatBackgroundHelper(View view) {
mView = view;
}
public void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.SkinBackgroundHelper, defStyleAttr, 0);
try {
if (a.hasValue(R.styleable.SkinBackgroundHelper_android_background)) {
mBackgroundResId = a.getResourceId(
R.styleable.SkinBackgroundHelper_android_background, INVALID_ID);
}
} finally {
a.recycle();
}
applySkin();
}
public void onSetBackgroundResource(int resId) {
mBackgroundResId = resId;
// Update the default background tint
applySkin();
}
@Override
public void applySkin() {
mBackgroundResId = checkResourceId(mBackgroundResId);
if (mBackgroundResId == INVALID_ID) {
return;
}
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mBackgroundResId);
if (drawable != null) {
int paddingLeft = mView.getPaddingLeft();
int paddingTop = mView.getPaddingTop();
int paddingRight = mView.getPaddingRight();
int paddingBottom = mView.getPaddingBottom();
ViewCompat.setBackground(mView, drawable);
mView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
}
}

View File

@@ -0,0 +1,81 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.R;
import androidx.appcompat.widget.AppCompatButton;
import android.util.AttributeSet;
/**
* Created by ximsfei on 17-1-11.
*/
public class SkinCompatButton extends AppCompatButton implements SkinCompatSupportable {
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatButton(Context context) {
this(context, null);
}
public SkinCompatButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.buttonStyle);
}
public SkinCompatButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,97 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatCheckBox;
import android.util.AttributeSet;
import skin.support.appcompat.R;
/**
* Created by ximsfei on 17-1-14.
*/
public class SkinCompatCheckBox extends AppCompatCheckBox implements SkinCompatSupportable {
private SkinCompatCompoundButtonHelper mCompoundButtonHelper;
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatCheckBox(Context context) {
this(context, null);
}
public SkinCompatCheckBox(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.checkboxStyle);
}
public SkinCompatCheckBox(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCompoundButtonHelper = new SkinCompatCompoundButtonHelper(this);
mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setButtonDrawable(@DrawableRes int resId) {
super.setButtonDrawable(resId);
if (mCompoundButtonHelper != null) {
mCompoundButtonHelper.setButtonDrawable(resId);
}
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mCompoundButtonHelper != null) {
mCompoundButtonHelper.applySkin();
}
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,111 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatCheckedTextView;
import android.util.AttributeSet;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatVectorResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 17-1-14.
*/
public class SkinCompatCheckedTextView extends AppCompatCheckedTextView implements SkinCompatSupportable {
private static final int[] TINT_ATTRS = {
android.R.attr.checkMark
};
private int mCheckMarkResId = INVALID_ID;
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatCheckedTextView(Context context) {
this(context, null);
}
public SkinCompatCheckedTextView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.checkedTextViewStyle);
}
public SkinCompatCheckedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, TINT_ATTRS, defStyleAttr, 0);
mCheckMarkResId = a.getResourceId(0, INVALID_ID);
a.recycle();
applyCheckMark();
}
@Override
public void setCheckMarkDrawable(@DrawableRes int resId) {
mCheckMarkResId = resId;
applyCheckMark();
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
applyCheckMark();
}
private void applyCheckMark() {
mCheckMarkResId = SkinCompatHelper.checkResourceId(mCheckMarkResId);
if (mCheckMarkResId != INVALID_ID) {
setCheckMarkDrawable(SkinCompatVectorResources.getDrawableCompat(getContext(), mCheckMarkResId));
}
}
}

View File

@@ -0,0 +1,58 @@
package skin.support.widget;
import android.content.res.TypedArray;
import androidx.core.widget.CompoundButtonCompat;
import android.util.AttributeSet;
import android.widget.CompoundButton;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by ximsfei on 17-1-14.
*/
public class SkinCompatCompoundButtonHelper extends SkinCompatHelper {
private final CompoundButton mView;
private int mButtonResourceId = INVALID_ID;
private int mButtonTintResId = INVALID_ID;
public SkinCompatCompoundButtonHelper(CompoundButton view) {
mView = view;
}
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.CompoundButton,
defStyleAttr, INVALID_ID);
try {
if (a.hasValue(R.styleable.CompoundButton_android_button)) {
mButtonResourceId = a.getResourceId(
R.styleable.CompoundButton_android_button, INVALID_ID);
}
if (a.hasValue(R.styleable.CompoundButton_buttonTint)) {
mButtonTintResId = a.getResourceId(R.styleable.CompoundButton_buttonTint, INVALID_ID);
}
} finally {
a.recycle();
}
applySkin();
}
public void setButtonDrawable(int resId) {
mButtonResourceId = resId;
applySkin();
}
@Override
public void applySkin() {
mButtonResourceId = SkinCompatHelper.checkResourceId(mButtonResourceId);
if (mButtonResourceId != INVALID_ID) {
mView.setButtonDrawable(SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mButtonResourceId));
}
mButtonTintResId = SkinCompatHelper.checkResourceId(mButtonTintResId);
if (mButtonTintResId != INVALID_ID) {
CompoundButtonCompat.setButtonTintList(mView, SkinCompatResources.getColorStateList(mView.getContext(), mButtonTintResId));
}
}
}

View File

@@ -0,0 +1,88 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.R;
import androidx.appcompat.widget.AppCompatEditText;
import android.util.AttributeSet;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 2017/1/10.
*/
public class SkinCompatEditText extends AppCompatEditText implements SkinCompatSupportable {
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatEditText(Context context) {
this(context, null);
}
public SkinCompatEditText(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextStyle);
}
public SkinCompatEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
public int getTextColorResId() {
return mTextHelper != null ? mTextHelper.getTextColorResId() : INVALID_ID;
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,43 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
/**
* Created by pengfengwang on 2017/1/13.
*/
public class SkinCompatFrameLayout extends FrameLayout implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatFrameLayout(Context context) {
this(context, null);
}
public SkinCompatFrameLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,60 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.R;
import androidx.appcompat.widget.AppCompatImageButton;
import android.util.AttributeSet;
/**
* Created by ximsfei on 17-1-13.
*/
public class SkinCompatImageButton extends AppCompatImageButton implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
private SkinCompatImageHelper mImageHelper;
public SkinCompatImageButton(Context context) {
this(context, null);
}
public SkinCompatImageButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.imageButtonStyle);
}
public SkinCompatImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mImageHelper = new SkinCompatImageHelper(this);
mImageHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setImageResource(@DrawableRes int resId) {
// Intercept this call and instead retrieve the Drawable via the image helper
if (mImageHelper != null) {
mImageHelper.setImageResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mImageHelper != null) {
mImageHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,76 @@
package skin.support.widget;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import androidx.core.widget.ImageViewCompat;
import skin.support.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by ximsfei on 2017/1/12.
*/
public class SkinCompatImageHelper extends SkinCompatHelper {
private static final String TAG = SkinCompatImageHelper.class.getSimpleName();
private final ImageView mView;
private int mSrcResId = INVALID_ID;
private int mSrcCompatResId = INVALID_ID;
private int mSrcTintResId = INVALID_ID;
public SkinCompatImageHelper(ImageView imageView) {
mView = imageView;
}
public void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
TypedArray a = null;
try {
a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.SkinCompatImageView, defStyleAttr, 0);
mSrcResId = a.getResourceId(R.styleable.SkinCompatImageView_android_src, INVALID_ID);
mSrcCompatResId = a.getResourceId(R.styleable.SkinCompatImageView_srcCompat, INVALID_ID);
mSrcTintResId = a.getResourceId(R.styleable.SkinCompatImageView_tint, INVALID_ID);
if (mSrcTintResId == INVALID_ID) {
mSrcTintResId = a.getResourceId(R.styleable.SkinCompatImageView_android_tint, INVALID_ID);
}
} finally {
if (a != null) {
a.recycle();
}
}
applySkin();
}
public void setImageResource(int resId) {
mSrcResId = resId;
mSrcCompatResId = INVALID_ID;
applySkin();
}
@Override
public void applySkin() {
mSrcCompatResId = checkResourceId(mSrcCompatResId);
if (mSrcCompatResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mSrcCompatResId);
if (drawable != null) {
mView.setImageDrawable(drawable);
}
} else {
mSrcResId = checkResourceId(mSrcResId);
if (mSrcResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mSrcResId);
if (drawable != null) {
mView.setImageDrawable(drawable);
}
}
}
mSrcTintResId = checkResourceId(mSrcTintResId);
if (mSrcTintResId != INVALID_ID) {
ColorStateList tintList = SkinCompatResources.getColorStateList(mView.getContext(), mSrcTintResId);
ImageViewCompat.setImageTintList(mView, tintList);
}
}
}

View File

@@ -0,0 +1,59 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatImageView;
import android.util.AttributeSet;
/**
* Created by ximsfei on 2017/1/10.
*/
public class SkinCompatImageView extends AppCompatImageView implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
private SkinCompatImageHelper mImageHelper;
public SkinCompatImageView(Context context) {
this(context, null);
}
public SkinCompatImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mImageHelper = new SkinCompatImageHelper(this);
mImageHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setImageResource(@DrawableRes int resId) {
// Intercept this call and instead retrieve the Drawable via the image helper
if (mImageHelper != null) {
mImageHelper.setImageResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mImageHelper != null) {
mImageHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,43 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/**
* Created by pengfengwang on 2017/1/13.
*/
public class SkinCompatLinearLayout extends LinearLayout implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatLinearLayout(Context context) {
this(context, null);
}
public SkinCompatLinearLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,117 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatMultiAutoCompleteTextView;
import android.util.AttributeSet;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatVectorResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* @author ximsfei
* @date 17-1-14
*/
public class SkinCompatMultiAutoCompleteTextView extends AppCompatMultiAutoCompleteTextView implements SkinCompatSupportable {
private static final int[] TINT_ATTRS = {
android.R.attr.popupBackground
};
private int mDropDownBackgroundResId = INVALID_ID;
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatMultiAutoCompleteTextView(Context context) {
this(context, null);
}
public SkinCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextStyle);
}
public SkinCompatMultiAutoCompleteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, TINT_ATTRS, defStyleAttr, 0);
if (a.hasValue(0)) {
mDropDownBackgroundResId = a.getResourceId(0, INVALID_ID);
}
a.recycle();
applyDropDownBackgroundResource();
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setDropDownBackgroundResource(@DrawableRes int resId) {
super.setDropDownBackgroundResource(resId);
mDropDownBackgroundResId = resId;
applyDropDownBackgroundResource();
}
private void applyDropDownBackgroundResource() {
mDropDownBackgroundResId = SkinCompatHelper.checkResourceId(mDropDownBackgroundResId);
if (mDropDownBackgroundResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(getContext(), mDropDownBackgroundResId);
if (drawable != null) {
setDropDownBackgroundDrawable(drawable);
}
}
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
applyDropDownBackgroundResource();
}
}

View File

@@ -0,0 +1,35 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ProgressBar;
/**
* Created by ximsfei on 2017/1/19.
*/
public class SkinCompatProgressBar extends ProgressBar implements SkinCompatSupportable {
private SkinCompatProgressBarHelper mSkinCompatProgressBarHelper;
public SkinCompatProgressBar(Context context) {
this(context, null);
}
public SkinCompatProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.progressBarStyle);
}
public SkinCompatProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mSkinCompatProgressBarHelper = new SkinCompatProgressBarHelper(this);
mSkinCompatProgressBarHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void applySkin() {
if (mSkinCompatProgressBarHelper != null) {
mSkinCompatProgressBarHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,164 @@
package skin.support.widget;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Shader;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ProgressBar;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
import skin.support.utils.SkinCompatVersionUtils;
/**
* Created by ximsfei on 2017/1/20.
*/
public class SkinCompatProgressBarHelper extends SkinCompatHelper {
private final ProgressBar mView;
private Bitmap mSampleTile;
private int mIndeterminateDrawableResId = INVALID_ID;
private int mProgressDrawableResId = INVALID_ID;
private int mIndeterminateTintResId = INVALID_ID;
SkinCompatProgressBarHelper(ProgressBar view) {
mView = view;
}
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.SkinCompatProgressBar, defStyleAttr, 0);
mIndeterminateDrawableResId = a.getResourceId(R.styleable.SkinCompatProgressBar_android_indeterminateDrawable, INVALID_ID);
mProgressDrawableResId = a.getResourceId(R.styleable.SkinCompatProgressBar_android_progressDrawable, INVALID_ID);
a.recycle();
if (Build.VERSION.SDK_INT > 21) {
a = mView.getContext().obtainStyledAttributes(attrs, new int[]{android.R.attr.indeterminateTint}, defStyleAttr, 0);
mIndeterminateTintResId = a.getResourceId(0, INVALID_ID);
a.recycle();
}
applySkin();
}
/**
* Converts a drawable to a tiled version of itself. It will recursively
* traverse layer and state list drawables.
*/
private Drawable tileify(Drawable drawable, boolean clip) {
if (SkinCompatVersionUtils.isV4WrappedDrawable(drawable)) {
Drawable inner = SkinCompatVersionUtils.getV4WrappedDrawableWrappedDrawable(drawable);
if (inner != null) {
inner = tileify(inner, clip);
SkinCompatVersionUtils.setV4WrappedDrawableWrappedDrawable(drawable, inner);
}
} else if (SkinCompatVersionUtils.isV4DrawableWrapper(drawable)) {
Drawable inner = SkinCompatVersionUtils.getV4DrawableWrapperWrappedDrawable(drawable);
if (inner != null) {
inner = tileify(inner, clip);
SkinCompatVersionUtils.setV4DrawableWrapperWrappedDrawable(drawable, inner);
}
} else if (drawable instanceof LayerDrawable) {
LayerDrawable background = (LayerDrawable) drawable;
final int N = background.getNumberOfLayers();
Drawable[] outDrawables = new Drawable[N];
for (int i = 0; i < N; i++) {
int id = background.getId(i);
outDrawables[i] = tileify(background.getDrawable(i),
(id == android.R.id.progress || id == android.R.id.secondaryProgress));
}
LayerDrawable newBg = new LayerDrawable(outDrawables);
for (int i = 0; i < N; i++) {
newBg.setId(i, background.getId(i));
}
return newBg;
} else if (drawable instanceof BitmapDrawable) {
final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
final Bitmap tileBitmap = bitmapDrawable.getBitmap();
if (mSampleTile == null) {
mSampleTile = tileBitmap;
}
final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
shapeDrawable.getPaint().setShader(bitmapShader);
shapeDrawable.getPaint().setColorFilter(bitmapDrawable.getPaint().getColorFilter());
return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
ClipDrawable.HORIZONTAL) : shapeDrawable;
}
return drawable;
}
/**
* Convert a AnimationDrawable for use as a barberpole animation.
* Each frame of the animation is wrapped in a ClipDrawable and
* given a tiling BitmapShader.
*/
private Drawable tileifyIndeterminate(Drawable drawable) {
if (drawable instanceof AnimationDrawable) {
AnimationDrawable background = (AnimationDrawable) drawable;
final int N = background.getNumberOfFrames();
AnimationDrawable newBg = new AnimationDrawable();
newBg.setOneShot(background.isOneShot());
for (int i = 0; i < N; i++) {
Drawable frame = tileify(background.getFrame(i), true);
frame.setLevel(10000);
newBg.addFrame(frame, background.getDuration(i));
}
newBg.setLevel(10000);
drawable = newBg;
}
return drawable;
}
private Shape getDrawableShape() {
final float[] roundedCorners = new float[]{5, 5, 5, 5, 5, 5, 5, 5};
return new RoundRectShape(roundedCorners, null, null);
}
@Override
public void applySkin() {
mIndeterminateDrawableResId = checkResourceId(mIndeterminateDrawableResId);
if (mIndeterminateDrawableResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mIndeterminateDrawableResId);
drawable.setBounds(mView.getIndeterminateDrawable().getBounds());
mView.setIndeterminateDrawable(tileifyIndeterminate(drawable));
}
mProgressDrawableResId = checkProgressDrawableResId(mProgressDrawableResId);
if (mProgressDrawableResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mProgressDrawableResId);
mView.setProgressDrawable(tileify(drawable, false));
}
if (Build.VERSION.SDK_INT > 21) {
mIndeterminateTintResId = checkResourceId(mIndeterminateTintResId);
if (mIndeterminateTintResId != INVALID_ID) {
mView.setIndeterminateTintList(SkinCompatResources.getColorStateList(mView.getContext(), mIndeterminateTintResId));
}
}
}
private int checkProgressDrawableResId(int mProgressDrawableResId) {
return checkResourceId(mProgressDrawableResId);
}
}

View File

@@ -0,0 +1,97 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatRadioButton;
import android.util.AttributeSet;
import skin.support.appcompat.R;
/**
* Created by ximsfei on 17-1-14.
*/
public class SkinCompatRadioButton extends AppCompatRadioButton implements SkinCompatSupportable {
private SkinCompatTextHelper mTextHelper;
private SkinCompatCompoundButtonHelper mCompoundButtonHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatRadioButton(Context context) {
this(context, null);
}
public SkinCompatRadioButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.radioButtonStyle);
}
public SkinCompatRadioButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCompoundButtonHelper = new SkinCompatCompoundButtonHelper(this);
mCompoundButtonHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setButtonDrawable(@DrawableRes int resId) {
super.setButtonDrawable(resId);
if (mCompoundButtonHelper != null) {
mCompoundButtonHelper.setButtonDrawable(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mCompoundButtonHelper != null) {
mCompoundButtonHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,37 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RadioGroup;
/**
* Created by ximsf on 2017/3/23.
*/
public class SkinCompatRadioGroup extends RadioGroup implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatRadioGroup(Context context) {
this(context, null);
}
public SkinCompatRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, 0);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,37 @@
package skin.support.widget;
import android.content.Context;
import androidx.appcompat.widget.AppCompatRatingBar;
import android.util.AttributeSet;
import skin.support.appcompat.R;
/**
* Created by ximsfei on 17-1-21.
*/
public class SkinCompatRatingBar extends AppCompatRatingBar implements SkinCompatSupportable {
private SkinCompatProgressBarHelper mSkinCompatProgressBarHelper;
public SkinCompatRatingBar(Context context) {
this(context, null);
}
public SkinCompatRatingBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.ratingBarStyle);
}
public SkinCompatRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mSkinCompatProgressBarHelper = new SkinCompatProgressBarHelper(this);
mSkinCompatProgressBarHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void applySkin() {
if (mSkinCompatProgressBarHelper != null) {
mSkinCompatProgressBarHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,43 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
/**
* Created by pengfengwang on 2017/1/13.
*/
public class SkinCompatRelativeLayout extends RelativeLayout implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatRelativeLayout(Context context) {
this(context, null);
}
public SkinCompatRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,43 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import android.util.AttributeSet;
import android.widget.ScrollView;
/**
* Created by Jungle68 on 2017/6/27.
*/
public class SkinCompatScrollView extends ScrollView implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatScrollView(Context context) {
this(context, null);
}
public SkinCompatScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,38 @@
package skin.support.widget;
import android.content.Context;
import androidx.appcompat.widget.AppCompatSeekBar;
import android.util.AttributeSet;
import skin.support.appcompat.R;
/**
* Created by ximsfei on 17-1-21.
*/
public class SkinCompatSeekBar extends AppCompatSeekBar implements SkinCompatSupportable {
private SkinCompatSeekBarHelper mSkinCompatSeekBarHelper;
public SkinCompatSeekBar(Context context) {
this(context, null);
}
public SkinCompatSeekBar(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.seekBarStyle);
}
public SkinCompatSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mSkinCompatSeekBarHelper = new SkinCompatSeekBarHelper(this);
mSkinCompatSeekBarHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void applySkin() {
if (mSkinCompatSeekBarHelper != null) {
mSkinCompatSeekBarHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,43 @@
package skin.support.widget;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.SeekBar;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by ximsfei on 17-1-21.
*/
public class SkinCompatSeekBarHelper extends SkinCompatProgressBarHelper {
private final SeekBar mView;
private int mThumbResId = INVALID_ID;
public SkinCompatSeekBarHelper(SeekBar view) {
super(view);
mView = view;
}
@Override
void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
super.loadFromAttributes(attrs, defStyleAttr);
TypedArray a = mView.getContext().obtainStyledAttributes(attrs, R.styleable.AppCompatSeekBar, defStyleAttr, 0);
mThumbResId = a.getResourceId(R.styleable.AppCompatSeekBar_android_thumb, INVALID_ID);
a.recycle();
applySkin();
}
@Override
public void applySkin() {
super.applySkin();
mThumbResId = checkResourceId(mThumbResId);
if (mThumbResId != INVALID_ID) {
mView.setThumb(SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mThumbResId));
}
}
}

View File

@@ -0,0 +1,116 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatSpinner;
import android.util.AttributeSet;
import android.util.Log;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatVectorResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
import static skin.support.widget.SkinCompatHelper.checkResourceId;
/**
* Created by ximsfei on 17-1-21.
*/
public class SkinCompatSpinner extends AppCompatSpinner implements SkinCompatSupportable {
private static final String TAG = SkinCompatSpinner.class.getSimpleName();
private static final int[] ATTRS_ANDROID_SPINNERMODE = {android.R.attr.spinnerMode};
private static final int MODE_DIALOG = 0;
private static final int MODE_DROPDOWN = 1;
private static final int MODE_THEME = -1;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
private int mPopupBackgroundResId = INVALID_ID;
public SkinCompatSpinner(Context context) {
this(context, null);
}
public SkinCompatSpinner(Context context, int mode) {
this(context, null, R.attr.spinnerStyle, mode);
}
public SkinCompatSpinner(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.spinnerStyle);
}
public SkinCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, MODE_THEME);
}
public SkinCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
this(context, attrs, defStyleAttr, mode, null);
}
public SkinCompatSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode, Resources.Theme popupTheme) {
super(context, attrs, defStyleAttr, mode, popupTheme);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Spinner, defStyleAttr, 0);
if (getPopupContext() != null) {
if (mode == MODE_THEME) {
if (Build.VERSION.SDK_INT >= 11) {
// If we're running on API v11+ we will try and read android:spinnerMode
TypedArray aa = null;
try {
aa = context.obtainStyledAttributes(attrs, ATTRS_ANDROID_SPINNERMODE,
defStyleAttr, 0);
if (aa.hasValue(0)) {
mode = aa.getInt(0, MODE_DIALOG);
}
} catch (Exception e) {
Log.i(TAG, "Could not read android:spinnerMode", e);
} finally {
if (aa != null) {
aa.recycle();
}
}
} else {
// Else, we use a default mode of dropdown
mode = MODE_DROPDOWN;
}
}
if (mode == MODE_DROPDOWN) {
final TypedArray pa = getPopupContext().obtainStyledAttributes(attrs, R.styleable.Spinner, defStyleAttr, 0);
mPopupBackgroundResId = pa.getResourceId(R.styleable.Spinner_android_popupBackground, INVALID_ID);
pa.recycle();
}
}
a.recycle();
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setPopupBackgroundResource(@DrawableRes int resId) {
super.setPopupBackgroundResource(resId);
mPopupBackgroundResId = resId;
applyPopupBackground();
}
private void applyPopupBackground() {
mPopupBackgroundResId = checkResourceId(mPopupBackgroundResId);
if (mPopupBackgroundResId != INVALID_ID) {
setPopupBackgroundDrawable(SkinCompatVectorResources.getDrawableCompat(getContext(), mPopupBackgroundResId));
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
applyPopupBackground();
}
}

View File

@@ -0,0 +1,186 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import androidx.annotation.DrawableRes;
import android.util.AttributeSet;
import android.widget.TextView;
import skin.support.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by ximsfei on 2017/1/10.
*/
public class SkinCompatTextHelper extends SkinCompatHelper {
private static final String TAG = SkinCompatTextHelper.class.getSimpleName();
public static SkinCompatTextHelper create(TextView textView) {
if (Build.VERSION.SDK_INT >= 17) {
return new SkinCompatTextHelperV17(textView);
}
return new SkinCompatTextHelper(textView);
}
final TextView mView;
private int mTextColorResId = INVALID_ID;
private int mTextColorHintResId = INVALID_ID;
protected int mDrawableBottomResId = INVALID_ID;
protected int mDrawableLeftResId = INVALID_ID;
protected int mDrawableRightResId = INVALID_ID;
protected int mDrawableTopResId = INVALID_ID;
public SkinCompatTextHelper(TextView view) {
mView = view;
}
public void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
final Context context = mView.getContext();
// First read the TextAppearance style id
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SkinCompatTextHelper, defStyleAttr, 0);
final int ap = a.getResourceId(R.styleable.SkinCompatTextHelper_android_textAppearance, INVALID_ID);
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableLeft)) {
mDrawableLeftResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableLeft, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableTop)) {
mDrawableTopResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableTop, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableRight)) {
mDrawableRightResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableRight, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableBottom)) {
mDrawableBottomResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableBottom, INVALID_ID);
}
a.recycle();
if (ap != INVALID_ID) {
a = context.obtainStyledAttributes(ap, R.styleable.SkinTextAppearance);
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColor)) {
mTextColorResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColor, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColorHint)) {
mTextColorHintResId = a.getResourceId(
R.styleable.SkinTextAppearance_android_textColorHint, INVALID_ID);
}
a.recycle();
}
// Now read the style's values
a = context.obtainStyledAttributes(attrs, R.styleable.SkinTextAppearance, defStyleAttr, 0);
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColor)) {
mTextColorResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColor, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColorHint)) {
mTextColorHintResId = a.getResourceId(
R.styleable.SkinTextAppearance_android_textColorHint, INVALID_ID);
}
a.recycle();
applySkin();
}
public void onSetTextAppearance(Context context, int resId) {
final TypedArray a = context.obtainStyledAttributes(resId, R.styleable.SkinTextAppearance);
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColor)) {
mTextColorResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColor, INVALID_ID);
}
if (a.hasValue(R.styleable.SkinTextAppearance_android_textColorHint)) {
mTextColorHintResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColorHint, INVALID_ID);
}
a.recycle();
applyTextColorResource();
applyTextColorHintResource();
}
private void applyTextColorHintResource() {
mTextColorHintResId = checkResourceId(mTextColorHintResId);
if (mTextColorHintResId != INVALID_ID) {
// TODO: HTC_U-3u OS:8.0上调用framework的getColorStateList方法有可能抛出异常暂时没有找到更好的解决办法.
// issue: https://github.com/ximsfei/Android-skin-support/issues/110
try {
ColorStateList color = SkinCompatResources.getColorStateList(mView.getContext(), mTextColorHintResId);
mView.setHintTextColor(color);
} catch (Exception e) {
}
}
}
private void applyTextColorResource() {
mTextColorResId = checkResourceId(mTextColorResId);
if (mTextColorResId != INVALID_ID) {
// TODO: HTC_U-3u OS:8.0上调用framework的getColorStateList方法有可能抛出异常暂时没有找到更好的解决办法.
// issue: https://github.com/ximsfei/Android-skin-support/issues/110
try {
ColorStateList color = SkinCompatResources.getColorStateList(mView.getContext(), mTextColorResId);
mView.setTextColor(color);
} catch (Exception e) {
}
}
}
public void onSetCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
mDrawableLeftResId = start;
mDrawableTopResId = top;
mDrawableRightResId = end;
mDrawableBottomResId = bottom;
applyCompoundDrawablesRelativeResource();
}
public void onSetCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
mDrawableLeftResId = left;
mDrawableTopResId = top;
mDrawableRightResId = right;
mDrawableBottomResId = bottom;
applyCompoundDrawablesResource();
}
protected void applyCompoundDrawablesRelativeResource() {
applyCompoundDrawablesResource();
}
protected void applyCompoundDrawablesResource() {
Drawable drawableLeft = null, drawableTop = null, drawableRight = null, drawableBottom = null;
mDrawableLeftResId = checkResourceId(mDrawableLeftResId);
if (mDrawableLeftResId != INVALID_ID) {
drawableLeft = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableLeftResId);
}
mDrawableTopResId = checkResourceId(mDrawableTopResId);
if (mDrawableTopResId != INVALID_ID) {
drawableTop = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableTopResId);
}
mDrawableRightResId = checkResourceId(mDrawableRightResId);
if (mDrawableRightResId != INVALID_ID) {
drawableRight = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableRightResId);
}
mDrawableBottomResId = checkResourceId(mDrawableBottomResId);
if (mDrawableBottomResId != INVALID_ID) {
drawableBottom = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableBottomResId);
}
if (mDrawableLeftResId != INVALID_ID
|| mDrawableTopResId != INVALID_ID
|| mDrawableRightResId != INVALID_ID
|| mDrawableBottomResId != INVALID_ID) {
mView.setCompoundDrawablesWithIntrinsicBounds(drawableLeft, drawableTop, drawableRight, drawableBottom);
}
}
public int getTextColorResId() {
return mTextColorResId;
}
@Override
public void applySkin() {
applyCompoundDrawablesRelativeResource();
applyTextColorResource();
applyTextColorHintResource();
}
}

View File

@@ -0,0 +1,98 @@
package skin.support.widget;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import androidx.annotation.DrawableRes;
import androidx.annotation.RequiresApi;
import android.util.AttributeSet;
import android.widget.TextView;
import skin.support.R;
import skin.support.content.res.SkinCompatVectorResources;
/**
* Created by pengfengwang on 2017/3/8.
*/
@RequiresApi(17)
@TargetApi(17)
public class SkinCompatTextHelperV17 extends SkinCompatTextHelper {
private int mDrawableStartResId = INVALID_ID;
private int mDrawableEndResId = INVALID_ID;
public SkinCompatTextHelperV17(TextView view) {
super(view);
}
@Override
public void loadFromAttributes(AttributeSet attrs, int defStyleAttr) {
final Context context = mView.getContext();
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SkinCompatTextHelper,
defStyleAttr, 0);
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableStart)) {
mDrawableStartResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableStart, INVALID_ID);
mDrawableStartResId = SkinCompatHelper.checkResourceId(mDrawableStartResId);
}
if (a.hasValue(R.styleable.SkinCompatTextHelper_android_drawableEnd)) {
mDrawableEndResId = a.getResourceId(R.styleable.SkinCompatTextHelper_android_drawableEnd, INVALID_ID);
mDrawableEndResId = SkinCompatHelper.checkResourceId(mDrawableEndResId);
}
a.recycle();
super.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void onSetCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
mDrawableStartResId = start;
mDrawableTopResId = top;
mDrawableEndResId = end;
mDrawableBottomResId = bottom;
applyCompoundDrawablesRelativeResource();
}
@Override
protected void applyCompoundDrawablesRelativeResource() {
Drawable drawableLeft = null, drawableTop = null, drawableRight = null, drawableBottom = null,
drawableStart = null, drawableEnd = null;
mDrawableLeftResId = checkResourceId(mDrawableLeftResId);
if (mDrawableLeftResId != INVALID_ID) {
drawableLeft = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableLeftResId);
}
mDrawableTopResId = checkResourceId(mDrawableTopResId);
if (mDrawableTopResId != INVALID_ID) {
drawableTop = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableTopResId);
}
mDrawableRightResId = checkResourceId(mDrawableRightResId);
if (mDrawableRightResId != INVALID_ID) {
drawableRight = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableRightResId);
}
mDrawableBottomResId = checkResourceId(mDrawableBottomResId);
if (mDrawableBottomResId != INVALID_ID) {
drawableBottom = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableBottomResId);
}
if (mDrawableStartResId != INVALID_ID) {
drawableStart = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableStartResId);
}
if (drawableStart == null) {
drawableStart = drawableLeft;
}
if (mDrawableEndResId != INVALID_ID) {
drawableEnd = SkinCompatVectorResources.getDrawableCompat(mView.getContext(), mDrawableEndResId);
}
if (drawableEnd == null) {
drawableEnd = drawableRight;
}
if (mDrawableLeftResId != INVALID_ID
|| mDrawableTopResId != INVALID_ID
|| mDrawableRightResId != INVALID_ID
|| mDrawableBottomResId != INVALID_ID
|| mDrawableStartResId != INVALID_ID
|| mDrawableEndResId != INVALID_ID) {
mView.setCompoundDrawablesWithIntrinsicBounds(drawableStart, drawableTop, drawableEnd, drawableBottom);
}
}
}

View File

@@ -0,0 +1,81 @@
package skin.support.widget;
import android.content.Context;
import androidx.annotation.DrawableRes;
import androidx.appcompat.widget.AppCompatTextView;
import android.util.AttributeSet;
/**
* Created by ximsfei on 2017/1/10.
*/
public class SkinCompatTextView extends AppCompatTextView implements SkinCompatSupportable {
private SkinCompatTextHelper mTextHelper;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatTextView(Context context) {
this(context, null);
}
public SkinCompatTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public SkinCompatTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
mTextHelper = SkinCompatTextHelper.create(this);
mTextHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setTextAppearance(int resId) {
setTextAppearance(getContext(), resId);
}
@Override
public void setTextAppearance(Context context, int resId) {
super.setTextAppearance(context, resId);
if (mTextHelper != null) {
mTextHelper.onSetTextAppearance(context, resId);
}
}
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(
@DrawableRes int start, @DrawableRes int top, @DrawableRes int end, @DrawableRes int bottom) {
super.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
}
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(
@DrawableRes int left, @DrawableRes int top, @DrawableRes int right, @DrawableRes int bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
if (mTextHelper != null) {
mTextHelper.onSetCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
if (mTextHelper != null) {
mTextHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,114 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import android.util.AttributeSet;
import skin.support.appcompat.R;
import skin.support.content.res.SkinCompatResources;
import skin.support.content.res.SkinCompatVectorResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 17-1-12.
*/
public class SkinCompatToolbar extends Toolbar implements SkinCompatSupportable {
private int mTitleTextColorResId = INVALID_ID;
private int mSubtitleTextColorResId = INVALID_ID;
private int mNavigationIconResId = INVALID_ID;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatToolbar(Context context) {
this(context, null);
}
public SkinCompatToolbar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.attr.toolbarStyle);
}
public SkinCompatToolbar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar, defStyleAttr, 0);
mNavigationIconResId = a.getResourceId(R.styleable.Toolbar_navigationIcon, INVALID_ID);
int titleAp = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, INVALID_ID);
int subtitleAp = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, INVALID_ID);
a.recycle();
if (titleAp != INVALID_ID) {
a = context.obtainStyledAttributes(titleAp, R.styleable.SkinTextAppearance);
mTitleTextColorResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColor, INVALID_ID);
a.recycle();
}
if (subtitleAp != INVALID_ID) {
a = context.obtainStyledAttributes(subtitleAp, R.styleable.SkinTextAppearance);
mSubtitleTextColorResId = a.getResourceId(R.styleable.SkinTextAppearance_android_textColor, INVALID_ID);
a.recycle();
}
a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar, defStyleAttr, 0);
if (a.hasValue(R.styleable.Toolbar_titleTextColor)) {
mTitleTextColorResId = a.getResourceId(R.styleable.Toolbar_titleTextColor, INVALID_ID);
}
if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) {
mSubtitleTextColorResId = a.getResourceId(R.styleable.Toolbar_subtitleTextColor, INVALID_ID);
}
a.recycle();
applyTitleTextColor();
applySubtitleTextColor();
applyNavigationIcon();
}
private void applyTitleTextColor() {
mTitleTextColorResId = SkinCompatHelper.checkResourceId(mTitleTextColorResId);
if (mTitleTextColorResId != INVALID_ID) {
setTitleTextColor(SkinCompatResources.getColor(getContext(), mTitleTextColorResId));
}
}
private void applySubtitleTextColor() {
mSubtitleTextColorResId = SkinCompatHelper.checkResourceId(mSubtitleTextColorResId);
if (mSubtitleTextColorResId != INVALID_ID) {
setSubtitleTextColor(SkinCompatResources.getColor(getContext(), mSubtitleTextColorResId));
}
}
private void applyNavigationIcon() {
mNavigationIconResId = SkinCompatHelper.checkResourceId(mNavigationIconResId);
if (mNavigationIconResId != INVALID_ID) {
setNavigationIcon(SkinCompatVectorResources.getDrawableCompat(getContext(), mNavigationIconResId));
}
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void setNavigationIcon(@DrawableRes int resId) {
super.setNavigationIcon(resId);
mNavigationIconResId = resId;
applyNavigationIcon();
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
applyTitleTextColor();
applySubtitleTextColor();
applyNavigationIcon();
}
}

View File

@@ -0,0 +1,44 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by pengfengwang on 2017/1/13.
*/
public class SkinCompatView extends View implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatView(Context context) {
this(context, null);
}
public SkinCompatView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,40 @@
package skin.support.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
public abstract class SkinCompatViewGroup extends ViewGroup implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatViewGroup(Context context) {
this(context, null);
}
public SkinCompatViewGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/skin_btn_check_box" android:state_checked="true" />
<item android:drawable="@drawable/skin_btn_check_box_outline_blank" />
</selector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.11,0 2,-0.9 2,-2L21,5c0,-1.1 -0.89,-2 -2,-2zM10,17l-5,-5 1.41,-1.41L10,14.17l7.59,-7.59L19,8l-9,9z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,5v14H5V5h14m0,-2H5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/skin_btn_radio_checked" android:state_checked="true" />
<item android:drawable="@drawable/skin_btn_radio_unchecked" />
</selector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5 5,-2.24 5,-5 -2.24,-5 -5,-5zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z" />
</vector>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/parentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/skinAlertDialogBackground"
android:gravity="start|left|top"
android:orientation="vertical">
<include layout="@layout/skin_alert_dialog_title" />
<FrameLayout
android:id="@+id/contentPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp">
<View
android:id="@+id/scrollIndicatorUp"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="top"
android:background="?attr/skinAlertDialogControlHighlightColor"
android:visibility="gone" />
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.legacy.widget.Space
android:id="@+id/textSpacerNoTitle"
android:layout_width="match_parent"
android:layout_height="@dimen/abc_dialog_padding_top_material"
android:visibility="gone" />
<TextView
android:id="@android:id/message"
style="@style/TextAppearance.AppCompat.Subhead"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
android:textColor="?attr/skinAlertDialogMessageTextColor" />
<androidx.legacy.widget.Space
android:id="@+id/textSpacerNoButtons"
android:layout_width="match_parent"
android:layout_height="@dimen/skin_dialog_padding_top"
android:visibility="gone" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<View
android:id="@+id/scrollIndicatorDown"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_gravity="bottom"
android:background="?attr/skinAlertDialogControlHighlightColor"
android:visibility="gone" />
</FrameLayout>
<FrameLayout
android:id="@+id/customPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp">
<FrameLayout
android:id="@+id/custom"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</FrameLayout>
<include
layout="@layout/skin_alert_dialog_button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/buttonPanel"
style="?attr/buttonBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="true">
<androidx.appcompat.widget.ButtonBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="bottom"
android:orientation="horizontal"
android:paddingBottom="4dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:paddingTop="4dp">
<Button
android:id="@android:id/button3"
style="?attr/buttonBarNeutralButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/skinAlertDialogNeutralButtonTextColor" />
<androidx.legacy.widget.Space
android:id="@+id/spacer"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
android:visibility="invisible" />
<Button
android:id="@android:id/button2"
style="?attr/buttonBarNegativeButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/skinAlertDialogNegativeButtonTextColor" />
<Button
android:id="@android:id/button1"
style="?attr/buttonBarPositiveButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/skinAlertDialogPositiveButtonTextColor" />
</androidx.appcompat.widget.ButtonBarLayout>
</ScrollView>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- If the client uses a customTitle, it will be added here. -->
<LinearLayout
android:id="@+id/title_template"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|start|left"
android:orientation="horizontal"
android:paddingLeft="?attr/dialogPreferredPadding"
android:paddingRight="?attr/dialogPreferredPadding"
android:paddingTop="@dimen/skin_dialog_padding_top">
<ImageView
android:id="@android:id/icon"
android:layout_width="32dip"
android:layout_height="32dip"
android:layout_marginEnd="8dip"
android:layout_marginRight="8dip"
android:scaleType="fitCenter"
android:src="@null" />
<TextView
android:id="@+id/alertTitle"
style="?android:attr/windowTitleStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?attr/skinAlertDialogTitleTextColor"
android:ellipsize="end"
android:singleLine="true" />
</LinearLayout>
<androidx.legacy.widget.Space
android:id="@+id/titleDividerNoCustom"
android:layout_width="match_parent"
android:layout_height="@dimen/skin_dialog_title_divider"
android:visibility="gone" />
</LinearLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This layout file is used by the AlertDialog when displaying a list of items.
This layout file is inflated and used as the ListView to display the items.
Assign an ID so its state will be saved/restored.
-->
<view xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/select_dialog_listview"
style="@style/Widget.AppCompat.ListView"
class="androidx.appcompat.app.AlertController$RecycleListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="@null"
android:clipToPadding="false"
android:divider="?attr/skinAlertDialogListDivider"
android:fadingEdge="none"
android:overScrollMode="ifContentScrolls"
android:scrollbars="vertical"
app:paddingBottomNoButtons="@dimen/skin_dialog_list_padding_bottom_no_buttons"
app:paddingTopNoTitle="@dimen/skin_dialog_list_padding_top_no_title" />

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This layout file is used by the AlertDialog when displaying a list of items.
This layout file is inflated and used as the TextView to display individual
items.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:textAppearance="?attr/textAppearanceListItemSmall"
android:textColor="?attr/skinAlertDialogListItemTextColor" />

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="?attr/skinListChoiceIndicatorMultiple"
android:drawablePadding="20dp"
android:drawableStart="?attr/skinListChoiceIndicatorMultiple"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingLeft="@dimen/skin_select_dialog_padding_start"
android:paddingRight="?attr/dialogPreferredPadding"
android:paddingStart="@dimen/skin_select_dialog_padding_start"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?attr/skinAlertDialogListItemTextColor" />

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableLeft="?attr/skinListChoiceIndicatorSingle"
android:drawablePadding="20dp"
android:drawableStart="?attr/skinListChoiceIndicatorSingle"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:minHeight="?attr/listPreferredItemHeightSmall"
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingLeft="@dimen/skin_select_dialog_padding_start"
android:paddingRight="?attr/dialogPreferredPadding"
android:paddingStart="@dimen/skin_select_dialog_padding_start"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?attr/skinAlertDialogListItemTextColor" />

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="skinAlertDialogBackground" format="reference" />
<attr name="skinAlertDialogTitleTextColor" format="reference" />
<attr name="skinAlertDialogMessageTextColor" format="reference" />
<attr name="skinAlertDialogNeutralButtonTextColor" format="reference" />
<attr name="skinAlertDialogNegativeButtonTextColor" format="reference" />
<attr name="skinAlertDialogPositiveButtonTextColor" format="reference" />
<attr name="skinAlertDialogControlHighlightColor" format="reference" />
<attr name="skinAlertDialogListDivider" format="reference" />
<attr name="skinAlertDialogListItemTextColor" format="reference" />
<attr name="skinListChoiceIndicatorMultiple" format="reference" />
<attr name="skinListChoiceIndicatorSingle" format="reference" />
</resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="skin_dialog_padding_top">18dp</dimen>
<dimen name="skin_dialog_title_divider">8dp</dimen>
<dimen name="skin_dialog_list_padding_bottom_no_buttons">8dp</dimen>
<dimen name="skin_dialog_list_padding_top_no_title">8dp</dimen>
<dimen name="skin_select_dialog_padding_start">20dp</dimen>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AlertDialog.SkinCompat" parent="Base.AlertDialog.AppCompat">
<item name="android:layout">@layout/skin_alert_dialog</item>
<item name="listLayout">@layout/skin_select_dialog</item>
<item name="listItemLayout">@layout/skin_select_dialog_item</item>
<item name="multiChoiceItemLayout">@layout/skin_select_dialog_multichoice</item>
<item name="singleChoiceItemLayout">@layout/skin_select_dialog_singlechoice</item>
</style>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">skin-support-appcompat</string>
</resources>

1
skin/skin-support-cardview/.gitignore vendored Executable file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,30 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxcardview
implementation project(':skin:skin-support')
}
ext {
moduleName = "skin-support-cardview"
descContent = "CardView-v7 换肤支持包"
}

17
skin/skin-support-cardview/proguard-rules.pro vendored Executable file
View File

@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Users\ximsf\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="skin.support.cardview" />

View File

@@ -0,0 +1,32 @@
package skin.support;
import android.content.Context;
import skin.support.app.SkinCardViewInflater;
/**
* Created by ximsfei on 2017/3/5.
*/
public class SkinCardViewManager {
private static volatile SkinCardViewManager sInstance;
public static SkinCardViewManager init(Context context) {
if (sInstance == null) {
synchronized (SkinCardViewManager.class) {
if (sInstance == null) {
sInstance = new SkinCardViewManager(context);
}
}
}
return sInstance;
}
public static SkinCardViewManager getInstance() {
return sInstance;
}
private SkinCardViewManager(Context context) {
SkinCompatManager.init(context).addInflater(new SkinCardViewInflater());
}
}

View File

@@ -0,0 +1,27 @@
package skin.support.app;
import android.content.Context;
import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import skin.support.widget.SkinCompatCardView;
/**
* Created by ximsf on 2017/3/5.
*/
public class SkinCardViewInflater implements SkinLayoutInflater {
@Override
public View createView(@NonNull Context context, final String name, @NonNull AttributeSet attrs) {
View view = null;
switch (name) {
case "androidx.cardview.widget.CardView":
view = new SkinCompatCardView(context, attrs);
break;
default:
break;
}
return view;
}
}

View File

@@ -0,0 +1,70 @@
package skin.support.widget;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Color;
import androidx.cardview.widget.CardView;
import android.util.AttributeSet;
import skin.support.cardview.R;
import skin.support.content.res.SkinCompatResources;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 2017/3/5.
*/
public class SkinCompatCardView extends CardView implements SkinCompatSupportable {
private static final int[] COLOR_BACKGROUND_ATTR = {android.R.attr.colorBackground};
private int mThemeColorBackgroundResId = INVALID_ID;
private int mBackgroundColorResId = INVALID_ID;
public SkinCompatCardView(Context context) {
this(context, null);
}
public SkinCompatCardView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatCardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr,
R.style.CardView);
if (a.hasValue(R.styleable.CardView_cardBackgroundColor)) {
mBackgroundColorResId = a.getResourceId(R.styleable.CardView_cardBackgroundColor, INVALID_ID);
} else {
final TypedArray aa = getContext().obtainStyledAttributes(COLOR_BACKGROUND_ATTR);
mThemeColorBackgroundResId = aa.getResourceId(0, INVALID_ID);
aa.recycle();
}
a.recycle();
applyBackgroundColorResource();
}
private void applyBackgroundColorResource() {
mBackgroundColorResId = SkinCompatHelper.checkResourceId(mBackgroundColorResId);
mThemeColorBackgroundResId = SkinCompatHelper.checkResourceId(mThemeColorBackgroundResId);
ColorStateList backgroundColor;
if (mBackgroundColorResId != INVALID_ID) {
backgroundColor = SkinCompatResources.getColorStateList(getContext(), mBackgroundColorResId);
setCardBackgroundColor(backgroundColor);
} else if (mThemeColorBackgroundResId != INVALID_ID) {
int themeColorBackground = SkinCompatResources.getColor(getContext(), mThemeColorBackgroundResId);
final float[] hsv = new float[3];
Color.colorToHSV(themeColorBackground, hsv);
backgroundColor = ColorStateList.valueOf(hsv[2] > 0.5f
? getResources().getColor(R.color.cardview_light_background)
: getResources().getColor(R.color.cardview_dark_background));
setCardBackgroundColor(backgroundColor);
}
}
@Override
public void applySkin() {
applyBackgroundColorResource();
}
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Skin-Support-CardView</string>
</resources>

View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,31 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxconstraintlayout
implementation project(':skin:skin-support')
implementation project(':skin:skin-support-appcompat')
}
ext {
moduleName = 'skin-support-constraint-layout'
descContent = 'ConstraintLayout控件换肤支持包'
}

View File

@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ximsfei/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="skin.support.constraint" />

View File

@@ -0,0 +1,45 @@
package skin.support.constraint;
import android.content.Context;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.util.AttributeSet;
import skin.support.widget.SkinCompatBackgroundHelper;
import skin.support.widget.SkinCompatSupportable;
/**
* Created by pengfengwang on 2017/6/19.
*/
public class SkinCompatConstraintLayout extends ConstraintLayout implements SkinCompatSupportable {
private final SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinCompatConstraintLayout(Context context) {
this(context, null);
}
public SkinCompatConstraintLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinCompatConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
}
@Override
public void setBackgroundResource(int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,33 @@
package skin.support.constraint;
import android.content.Context;
import skin.support.SkinCompatManager;
import skin.support.constraint.app.SkinConstraintViewInflater;
/**
* Created by ximsfei on 2017/1/13.
*/
public class SkinConstraintManager {
private static volatile SkinConstraintManager sInstance;
public static SkinConstraintManager init(Context context) {
if (sInstance == null) {
synchronized (SkinConstraintManager.class) {
if (sInstance == null) {
sInstance = new SkinConstraintManager(context);
}
}
}
return sInstance;
}
public static SkinConstraintManager getInstance() {
return sInstance;
}
private SkinConstraintManager(Context context) {
SkinCompatManager.init(context).addInflater(new SkinConstraintViewInflater());
}
}

View File

@@ -0,0 +1,23 @@
package skin.support.constraint.app;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import skin.support.app.SkinLayoutInflater;
import skin.support.constraint.SkinCompatConstraintLayout;
public class SkinConstraintViewInflater implements SkinLayoutInflater {
@Override
public View createView(Context context, final String name, AttributeSet attrs) {
View view = null;
switch (name) {
case "androidx.constraintlayout.widget.ConstraintLayout":
view = new SkinCompatConstraintLayout(context, attrs);
break;
default:
break;
}
return view;
}
}

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Skin-support-constraint-layout</string>
</resources>

1
skin/skin-support-design/.gitignore vendored Executable file
View File

@@ -0,0 +1 @@
/build

View File

@@ -0,0 +1,31 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
// buildToolsVersion rootProject.ext.android.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation rootProject.ext.dependencies.androidxappcompat
implementation rootProject.ext.dependencies.material
implementation project(':skin:skin-support')
implementation project(':skin:skin-support-appcompat')
}
ext {
moduleName = 'skin-support-design'
descContent = 'material design控件换肤支持包'
}

17
skin/skin-support-design/proguard-rules.pro vendored Executable file
View File

@@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/ximsfei/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# 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 *;
#}

View File

@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="skin.support.design" />

View File

@@ -0,0 +1,33 @@
package skin.support.design;
import android.content.Context;
import skin.support.SkinCompatManager;
import skin.support.design.app.SkinMaterialViewInflater;
/**
* Created by ximsfei on 2017/1/13.
*/
public class SkinMaterialManager {
private static volatile SkinMaterialManager sInstance;
public static SkinMaterialManager init(Context context) {
if (sInstance == null) {
synchronized (SkinMaterialManager.class) {
if (sInstance == null) {
sInstance = new SkinMaterialManager(context);
}
}
}
return sInstance;
}
public static SkinMaterialManager getInstance() {
return sInstance;
}
private SkinMaterialManager(Context context) {
SkinCompatManager.init(context).addInflater(new SkinMaterialViewInflater());
}
}

View File

@@ -0,0 +1,62 @@
package skin.support.design.app;
import android.content.Context;
import androidx.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import skin.support.app.SkinLayoutInflater;
import skin.support.design.widget.SkinMaterialAppBarLayout;
import skin.support.design.widget.SkinMaterialBottomNavigationView;
import skin.support.design.widget.SkinMaterialCollapsingToolbarLayout;
import skin.support.design.widget.SkinMaterialCoordinatorLayout;
import skin.support.design.widget.SkinMaterialFloatingActionButton;
import skin.support.design.widget.SkinMaterialNavigationView;
import skin.support.design.widget.SkinMaterialTabLayout;
import skin.support.design.widget.SkinMaterialTextInputEditText;
import skin.support.design.widget.SkinMaterialTextInputLayout;
/**
* Created by ximsfei on 2017/1/13.
*/
public class SkinMaterialViewInflater implements SkinLayoutInflater {
@Override
public View createView(@NonNull Context context, final String name, @NonNull AttributeSet attrs) {
if ("androidx.coordinatorlayout.widget.CoordinatorLayout".equals(name)) {
return new SkinMaterialCoordinatorLayout(context, attrs);
}
if (!name.startsWith("com.google.android.material.")) {
return null;
}
View view = null;
switch (name) {
case "com.google.android.material.appbar.AppBarLayout":
view = new SkinMaterialAppBarLayout(context, attrs);
break;
case "com.google.android.material.tabs.TabLayout":
view = new SkinMaterialTabLayout(context, attrs);
break;
case "com.google.android.material.textfield.TextInputLayout":
view = new SkinMaterialTextInputLayout(context, attrs);
break;
case "com.google.android.material.textfield.TextInputEditText":
view = new SkinMaterialTextInputEditText(context, attrs);
break;
case "com.google.android.material.navigation.NavigationView":
view = new SkinMaterialNavigationView(context, attrs);
break;
case "com.google.android.material.floatingactionbutton.FloatingActionButton":
view = new SkinMaterialFloatingActionButton(context, attrs);
break;
case "com.google.android.material.bottomnavigation.BottomNavigationView":
view = new SkinMaterialBottomNavigationView(context, attrs);
break;
case "com.google.android.material.appbar.CollapsingToolbarLayout":
view = new SkinMaterialCollapsingToolbarLayout(context, attrs);
break;
default:
break;
}
return view;
}
}

View File

@@ -0,0 +1,34 @@
package skin.support.design.widget;
import android.content.Context;
import com.google.android.material.appbar.AppBarLayout;
import android.util.AttributeSet;
import skin.support.widget.SkinCompatBackgroundHelper;
import skin.support.widget.SkinCompatSupportable;
/**
* Created by ximsfei on 2017/1/13.
*/
public class SkinMaterialAppBarLayout extends AppBarLayout implements SkinCompatSupportable {
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinMaterialAppBarLayout(Context context) {
this(context, null);
}
public SkinMaterialAppBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, 0);
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

View File

@@ -0,0 +1,136 @@
package skin.support.design.widget;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import android.util.AttributeSet;
import android.util.TypedValue;
import skin.support.content.res.SkinCompatResources;
import skin.support.design.R;
import skin.support.widget.SkinCompatBackgroundHelper;
import skin.support.widget.SkinCompatHelper;
import skin.support.widget.SkinCompatSupportable;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 17-3-1.
*/
public class SkinMaterialBottomNavigationView extends BottomNavigationView implements SkinCompatSupportable {
private static final int[] DISABLED_STATE_SET = new int[]{-android.R.attr.state_enabled};
private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
private SkinCompatBackgroundHelper mBackgroundTintHelper;
private int mTextColorResId = INVALID_ID;
private int mIconTintResId = INVALID_ID;
private int mDefaultTintResId = INVALID_ID;
public SkinMaterialBottomNavigationView(@NonNull Context context) {
this(context, null);
}
public SkinMaterialBottomNavigationView(@NonNull Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinMaterialBottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BottomNavigationView, defStyleAttr,
R.style.Widget_Design_BottomNavigationView);
if (a.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
mIconTintResId = a.getResourceId(R.styleable.BottomNavigationView_itemIconTint, INVALID_ID);
} else {
mDefaultTintResId = resolveColorPrimary();
}
if (a.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
mTextColorResId = a.getResourceId(R.styleable.BottomNavigationView_itemTextColor, INVALID_ID);
} else {
mDefaultTintResId = resolveColorPrimary();
}
a.recycle();
applyItemIconTintResource();
applyItemTextColorResource();
}
@Override
public void setBackgroundResource(@DrawableRes int resId) {
super.setBackgroundResource(resId);
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.onSetBackgroundResource(resId);
}
}
private void applyItemTextColorResource() {
mTextColorResId = SkinCompatHelper.checkResourceId(mTextColorResId);
if (mTextColorResId != INVALID_ID) {
setItemTextColor(SkinCompatResources.getColorStateList(getContext(), mTextColorResId));
} else {
mDefaultTintResId = SkinCompatHelper.checkResourceId(mDefaultTintResId);
if (mDefaultTintResId != INVALID_ID) {
setItemTextColor(createDefaultColorStateList(android.R.attr.textColorSecondary));
}
}
}
private void applyItemIconTintResource() {
mIconTintResId = SkinCompatHelper.checkResourceId(mIconTintResId);
if (mIconTintResId != INVALID_ID) {
setItemIconTintList(SkinCompatResources.getColorStateList(getContext(), mIconTintResId));
} else {
mDefaultTintResId = SkinCompatHelper.checkResourceId(mDefaultTintResId);
if (mDefaultTintResId != INVALID_ID) {
setItemIconTintList(createDefaultColorStateList(android.R.attr.textColorSecondary));
}
}
}
private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
final TypedValue value = new TypedValue();
if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
return null;
}
ColorStateList baseColor = SkinCompatResources.getColorStateList(getContext(), value.resourceId);
int colorPrimary = SkinCompatResources.getColor(getContext(), mDefaultTintResId);
int defaultColor = baseColor.getDefaultColor();
return new ColorStateList(new int[][]{
DISABLED_STATE_SET,
CHECKED_STATE_SET,
EMPTY_STATE_SET
}, new int[]{
baseColor.getColorForState(DISABLED_STATE_SET, defaultColor),
colorPrimary,
defaultColor
});
}
private int resolveColorPrimary() {
final TypedValue value = new TypedValue();
if (!getContext().getTheme().resolveAttribute(
R.attr.colorPrimary, value, true)) {
return INVALID_ID;
}
return value.resourceId;
}
@Override
public void applySkin() {
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
applyItemIconTintResource();
applyItemTextColorResource();
}
}

View File

@@ -0,0 +1,78 @@
package skin.support.design.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import android.util.AttributeSet;
import skin.support.content.res.SkinCompatVectorResources;
import skin.support.design.R;
import skin.support.widget.SkinCompatBackgroundHelper;
import skin.support.widget.SkinCompatHelper;
import skin.support.widget.SkinCompatSupportable;
import static skin.support.widget.SkinCompatHelper.INVALID_ID;
/**
* Created by ximsfei on 17-3-2.
*/
public class SkinMaterialCollapsingToolbarLayout extends CollapsingToolbarLayout implements SkinCompatSupportable {
private int mContentScrimResId = INVALID_ID;
private int mStatusBarScrimResId = INVALID_ID;
private SkinCompatBackgroundHelper mBackgroundTintHelper;
public SkinMaterialCollapsingToolbarLayout(Context context) {
this(context, null);
}
public SkinMaterialCollapsingToolbarLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SkinMaterialCollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CollapsingToolbarLayout, defStyleAttr,
R.style.Widget_Design_CollapsingToolbar);
mContentScrimResId = a.getResourceId(R.styleable.CollapsingToolbarLayout_contentScrim, INVALID_ID);
mStatusBarScrimResId = a.getResourceId(R.styleable.CollapsingToolbarLayout_statusBarScrim, INVALID_ID);
a.recycle();
applyContentScrimResource();
applyStatusBarScrimResource();
mBackgroundTintHelper = new SkinCompatBackgroundHelper(this);
mBackgroundTintHelper.loadFromAttributes(attrs, 0);
}
private void applyStatusBarScrimResource() {
mStatusBarScrimResId = SkinCompatHelper.checkResourceId(mStatusBarScrimResId);
if (mStatusBarScrimResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(getContext(), mStatusBarScrimResId);
if (drawable != null) {
setStatusBarScrim(drawable);
}
}
}
private void applyContentScrimResource() {
mContentScrimResId = SkinCompatHelper.checkResourceId(mContentScrimResId);
if (mContentScrimResId != INVALID_ID) {
Drawable drawable = SkinCompatVectorResources.getDrawableCompat(getContext(), mContentScrimResId);
if (drawable != null) {
setContentScrim(drawable);
}
}
}
@Override
public void applySkin() {
applyContentScrimResource();
applyStatusBarScrimResource();
if (mBackgroundTintHelper != null) {
mBackgroundTintHelper.applySkin();
}
}
}

Some files were not shown because too many files have changed in this diff Show More