diff --git a/app/build.gradle b/app/build.gradle index bf31fe2..1df021a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,35 +1,34 @@ -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:0.7.+' - } -} + apply plugin: 'android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-android' repositories { mavenCentral() } android { - compileSdkVersion 19 - buildToolsVersion "19.0.0" + compileSdkVersion 29 + buildToolsVersion "29.0.2" + + lintOptions { + abortOnError false + } defaultConfig { minSdkVersion 17 - targetSdkVersion 19 + targetSdkVersion 29 versionCode 1 versionName "1.0" } buildTypes { release { - runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' } } } dependencies { - compile 'com.android.support:support-v4:13.0.0' + compile 'com.android.support:support-v4:27.0.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/app/src/main/java/com/flavienlaurent/spanimated/CornerMarkSpan.java b/app/src/main/java/com/flavienlaurent/spanimated/CornerMarkSpan.java new file mode 100644 index 0000000..7078f8f --- /dev/null +++ b/app/src/main/java/com/flavienlaurent/spanimated/CornerMarkSpan.java @@ -0,0 +1,89 @@ +package com.flavienlaurent.spanimated; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.ReplacementSpan; + +/** + */ +public class CornerMarkSpan extends ReplacementSpan { + + private final int cornerHeight; + private final int cornerWidth; + private TextPaint mCornerPaint; + private Paint mTextPaint; + private int mWidth; + private String text = ""; + + private Drawable cornerDrawable; + private Rect mCornerBound; + private Context mContext; + + public CornerMarkSpan(Context context, Paint textPaint) { + mContext = context; + mTextPaint = textPaint; + + mCornerPaint = new TextPaint(); + mCornerPaint.setTextAlign(Paint.Align.CENTER); + mCornerPaint.setStyle(Paint.Style.FILL); + mCornerPaint.setColor(Color.WHITE); + mCornerPaint.setTextSize(mTextPaint.getTextSize() * 0.5f); + mCornerPaint.setAntiAlias(true); + + cornerDrawable = context.getResources().getDrawable(R.drawable.corner_back_two_digital); + + cornerHeight = dp2px(context, 15); + cornerWidth = dp2px(context, 15); + + mCornerBound = new Rect(0, 0, cornerWidth, cornerHeight); + cornerDrawable.setBounds(mCornerBound); + } + + /** + * dp转px + */ + public static int dp2px(Context context, float dp) { + return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f); + } + + + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + //return text with relative to the Paint + mWidth = (int) paint.measureText(text, start, end); + if (text == null) { + text = ""; + } + this.text = text.toString(); + return mWidth; + } + + @Override + public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { + //draw the frame with custom Paint +// float halfHeight = (bottom - top) / 2f; +// canvas.drawCircle(x, top + halfHeight, halfHeight, mPaint); + if (!TextUtils.isEmpty(this.text)) { + canvas.drawText(text, start, end, x, y, mTextPaint); + } + + canvas.save(); + canvas.translate(x, top - cornerHeight + 3); + cornerDrawable.draw(canvas); + canvas.restore(); + + canvas.save(); + canvas.translate(cornerWidth / 2f - 2, -cornerHeight - dp2px(mContext, 4)); + canvas.drawText("12", 0, 2, x, y, mCornerPaint); + canvas.restore(); + + +// canvas.drawRect(x, top, x + mWidth, bottom, mPaint); + } +} diff --git a/app/src/main/java/com/flavienlaurent/spanimated/ListNumberSpan.kt b/app/src/main/java/com/flavienlaurent/spanimated/ListNumberSpan.kt new file mode 100644 index 0000000..2013494 --- /dev/null +++ b/app/src/main/java/com/flavienlaurent/spanimated/ListNumberSpan.kt @@ -0,0 +1,90 @@ +package com.flavienlaurent.spanimated + +import android.content.Context +import android.graphics.* +import android.graphics.Paint.FontMetricsInt +import android.os.Build +import android.support.annotation.RequiresApi +import android.text.TextPaint +import android.text.style.ReplacementSpan +import com.flavienlaurent.spanimated.utils.SystemUtils + +@RequiresApi(Build.VERSION_CODES.LOLLIPOP) +class ListNumberSpan(var isGrayStatus: Boolean, var number:String = "", + var context: Context) : ReplacementSpan() { + + private val COLOR_SENTENCE_HIGH_LIGHT = Color.parseColor("#66F5FF9A") + private val UNSELECT_SENTENCE_BACKGROUND_COLOR = Color.parseColor("#08000000") + + private val backGroundColor: Int = Color.parseColor("#262626") + private val backGroundGrayColor: Int = Color.parseColor("#A7A7A7") + private val textColor: Int = Color.WHITE + + /** + * 圆角矩形 和 数字 底部重叠后,将圆角矩形往Y轴的偏移量 + */ + private val numberBaseLineYDelta = SystemUtils.dp2px(context, 3f) + private var mNumberWidth = 0 + + private val numberPaint: Paint = TextPaint() + private val mRectBackgroundPaint: Paint = Paint() + private val mRoundRectBackgroundPaint: Paint = Paint() + + + private val mRoundRectF = RectF() + private val roundRectRadius: Float = SystemUtils.dp2px(context, 6f).toFloat() + + /** + * 排除数字后的宽度 + */ + private val roundRectBackgroundWidth = SystemUtils.dp2px(context, 12f) + private val roundRectBackgroundHeight = SystemUtils.dp2px(context, 12f) + + init { + initPaint() + } + + + private fun initPaint() { + mRectBackgroundPaint.color = if (isGrayStatus) UNSELECT_SENTENCE_BACKGROUND_COLOR else COLOR_SENTENCE_HIGH_LIGHT + mRectBackgroundPaint.style = Paint.Style.FILL + + mRoundRectBackgroundPaint.color = if(isGrayStatus) backGroundGrayColor else backGroundColor + mRoundRectBackgroundPaint.isAntiAlias = true + + numberPaint.color = textColor + numberPaint.isAntiAlias = true + numberPaint.textSize = SystemUtils.sp2px(context, 9f).toFloat() + numberPaint.textAlign = Paint.Align.CENTER + } + + override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: FontMetricsInt?): Int { //return text with relative to the Paint + mNumberWidth = numberPaint.measureText(text, start, end).toInt() + mNumberWidth += roundRectBackgroundWidth + + return mNumberWidth + } + + override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { + canvas.drawRect(x, top.toFloat(), x + mNumberWidth, bottom.toFloat(), mRectBackgroundPaint) + val deltaY = (y - top - roundRectBackgroundHeight + numberBaseLineYDelta).toFloat() + + canvas.save() + canvas.translate(0f, (-numberBaseLineYDelta).toFloat()) + + canvas.save() + canvas.translate(0f, deltaY) + mRoundRectF.set(x, top.toFloat(), x + mNumberWidth, top.toFloat() + roundRectBackgroundHeight) + canvas.drawRoundRect(mRoundRectF, roundRectRadius, roundRectRadius, mRoundRectBackgroundPaint) + canvas.restore() + + canvas.save() + canvas.translate(mNumberWidth / 2f ,0f ) + canvas.drawText(number, 0, number.length, x, y.toFloat(), numberPaint) + canvas.restore() + + canvas.restore() + + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/flavienlaurent/spanimated/MainActivity.java b/app/src/main/java/com/flavienlaurent/spanimated/MainActivity.java index 2b66fe9..8bcaab2 100644 --- a/app/src/main/java/com/flavienlaurent/spanimated/MainActivity.java +++ b/app/src/main/java/com/flavienlaurent/spanimated/MainActivity.java @@ -11,9 +11,12 @@ import android.graphics.Color; import android.graphics.EmbossMaskFilter; import android.graphics.Typeface; +import android.os.Build; import android.os.Bundle; +import android.support.annotation.RequiresApi; import android.text.Layout; import android.text.SpannableString; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.AbsoluteSizeSpan; import android.text.style.AlignmentSpan; @@ -43,6 +46,8 @@ import android.widget.Spinner; import android.widget.TextView; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -58,6 +63,8 @@ public class MainActivity extends Activity { private Button mBtnDraw1; private Button mBtnDraw2; private Button mBtnDraw3; + private Button mBtnDrawListNum; + private Button mBtnDrawCornMark; private Button mBtnAnimateTypeWriter; private Button mBtnViewPager; private Button mBtnAnimateAb1; @@ -87,6 +94,8 @@ protected void onCreate(Bundle savedInstanceState) { mBtnDraw1 = (Button) findViewById(R.id.btn_draw1); mBtnDraw2 = (Button) findViewById(R.id.btn_draw2); mBtnDraw3 = (Button) findViewById(R.id.btn_draw3); + mBtnDrawListNum = (Button) findViewById(R.id.mBtnDrawListNum); + mBtnDrawCornMark = (Button) findViewById(R.id.btn_corner_mark); mBtnAnimateTypeWriter = (Button) findViewById(R.id.btn_animate_typewriter); mBtnReset = (Button) findViewById(R.id.btn_reset); mBtnViewPager = (Button) findViewById(R.id.btn_viewpager); @@ -121,6 +130,21 @@ public void onClick(View v) { } }); + mBtnDrawListNum.setOnClickListener(new View.OnClickListener() { + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + @Override + public void onClick(View v) { + reset(); + drawingListNumberSpan(); + } + }); + mBtnDrawCornMark.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + reset(); + drawingCornerMarkSpan(); + } + }); mBtnDraw2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -364,6 +388,30 @@ private void drawingSpan1() { mText.setText(mBaconIpsumSpannableString); } + private void drawingCornerMarkSpan() { + CornerMarkSpan cornerMarkSpan = new CornerMarkSpan(this, mText.getPaint()); + mSpans.add(cornerMarkSpan); + + WordPosition wordPosition = getWordPosition(mBaconIpsum); + mBaconIpsumSpannableString.setSpan(cornerMarkSpan, wordPosition.start, wordPosition.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + //refresh + mText.setText(mBaconIpsumSpannableString); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private void drawingListNumberSpan() { + String listNumber = "1234567890"; + Object spannable = new ListNumberSpan(false,listNumber, this); + mSpans.add(spannable); + + WordPosition wordPosition = getWordPosition(mBaconIpsum); + SpannableStringBuilder cacheString = new SpannableStringBuilder(mBaconIpsumSpannableString); + cacheString.insert(wordPosition.start, listNumber); + cacheString.setSpan(spannable, wordPosition.start, wordPosition.start + listNumber.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + //refresh + mText.setText(cacheString); + } + private void animateTypeWriter() { TypeWriterSpanGroup spanGroup = buildTypeWriterSpanGroup(0, mBaconIpsum.length() - 1); ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(spanGroup, TYPE_WRITER_GROUP_ALPHA_PROPERTY, 0.0f, 1.0f); diff --git a/app/src/main/java/com/flavienlaurent/spanimated/utils/SystemUtils.kt b/app/src/main/java/com/flavienlaurent/spanimated/utils/SystemUtils.kt new file mode 100644 index 0000000..e72b345 --- /dev/null +++ b/app/src/main/java/com/flavienlaurent/spanimated/utils/SystemUtils.kt @@ -0,0 +1,25 @@ +package com.flavienlaurent.spanimated.utils + +import android.content.Context + +object SystemUtils { + + /** + * 将dip或dp值转换为px值,保证尺寸大小不变 + */ + fun dp2px(context: Context, dipValue: Float): Int { + val scale = context.resources.displayMetrics.density + return (dipValue * scale + 0.5f).toInt() + } + + + /** + * 将sp值转换为px值,保证文字大小不变 + */ + fun sp2px(context: Context, spValue: Float): Int { + val fontScale = context.resources.displayMetrics.scaledDensity + return (spValue * fontScale + 0.5f).toInt() + } + + +} \ No newline at end of file diff --git a/app/src/main/res/drawable-mdpi/corner_drawbale.9.png b/app/src/main/res/drawable-mdpi/corner_drawbale.9.png new file mode 100644 index 0000000..9818625 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/corner_drawbale.9.png differ diff --git a/app/src/main/res/drawable-xhdpi/corner_back_one_digital.png b/app/src/main/res/drawable-xhdpi/corner_back_one_digital.png new file mode 100644 index 0000000..1b3ed08 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/corner_back_one_digital.png differ diff --git a/app/src/main/res/drawable-xhdpi/corner_back_three_digital.png b/app/src/main/res/drawable-xhdpi/corner_back_three_digital.png new file mode 100644 index 0000000..da5f172 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/corner_back_three_digital.png differ diff --git a/app/src/main/res/drawable-xhdpi/corner_back_two_digital.png b/app/src/main/res/drawable-xhdpi/corner_back_two_digital.png new file mode 100644 index 0000000..a171b3b Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/corner_back_two_digital.png differ diff --git a/app/src/main/res/drawable-xhdpi/default_corner_back_one_digital.png b/app/src/main/res/drawable-xhdpi/default_corner_back_one_digital.png new file mode 100644 index 0000000..0d147e9 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/default_corner_back_one_digital.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 410960a..a979a08 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -17,7 +17,8 @@ android:padding="18dp" android:text="@string/bacon_ipsum" android:textColor="@color/text_color" - android:textSize="16sp"/> + android:textSize="18sp" + android:lineSpacingExtra="6dp" />