Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angled updates #5

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ android {

dependencies {
api project(path: ':synth')
// implementation 'club.cred.android:synth:1.0.0'
// implementation 'club.cred.android:synth:1.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
Expand Down
10 changes: 10 additions & 0 deletions sample/src/main/res/drawable/bg_gradient.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="315"
android:startColor="#4be6a2"
android:endColor="#1c9574"
android:type="linear" />

</shape>
50 changes: 13 additions & 37 deletions sample/src/main/res/layout/fragment_gutter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,56 +43,32 @@
app:layout_constraintTop_toBottomOf="@+id/header_image"
app:srcCompat="@drawable/emboss_deboss_text" />

<club.cred.synth.views.PitView
android:id="@+id/pit_view"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginHorizontal="64dp"
android:layout_marginTop="50dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/emboss_text_image"
app:neuCornerRadius="14dp" />

<club.cred.synth.views.ElevatedView
android:id="@+id/elevated_view"
android:layout_width="0dp"
android:layout_height="120dp"
android:layout_marginHorizontal="64dp"
android:layout_height="250dp"
android:layout_marginHorizontal="56dp"
android:layout_marginTop="50dp"
android:layout_marginBottom="50dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/pit_view"
app:layout_constraintTop_toBottomOf="@id/emboss_text_image"
app:neuCornerRadius="14dp" />

<androidx.constraintlayout.widget.Barrier
android:id="@+id/bottom_barrier"
<club.cred.synth.views.ParallelogramLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="bottom"
app:barrierMargin="30dp"
app:constraint_referenced_ids="elevated_view" />

<androidx.constraintlayout.widget.Barrier
android:id="@+id/top_barrier"
android:layout_width="0dp"
android:layout_height="0dp"
app:barrierDirection="top"
app:barrierMargin="-30dp"
app:constraint_referenced_ids="pit_view" />

<View
android:id="@+id/border"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginHorizontal="34dp"
android:background="@drawable/gutter_border"
app:layout_constraintBottom_toBottomOf="@id/bottom_barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/top_barrier" />
app:layout_constraintStart_toStartOf="@id/elevated_view"
app:layout_constraintEnd_toEndOf="@id/elevated_view"
app:layout_constraintTop_toTopOf="@id/elevated_view"
app:layout_constraintBottom_toBottomOf="@id/elevated_view">
<View
android:background="@drawable/bg_gradient"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</club.cred.synth.views.ParallelogramLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
58 changes: 58 additions & 0 deletions synth/src/main/java/club/cred/synth/CanvasKtx.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ package club.cred.synth.helper
import android.graphics.Canvas
import android.graphics.LinearGradient
import android.graphics.Path
import android.graphics.PointF
import android.graphics.Region
import android.graphics.Shader
import android.os.Build
import android.text.TextPaint
import android.widget.TextView
import androidx.annotation.RequiresApi
import kotlin.math.hypot
import kotlin.math.tan

/**
* clips everything inside the rect.
Expand Down Expand Up @@ -69,3 +72,58 @@ fun TextView.setGradientTextColors(vararg colors: Int) {
val textShader: Shader = LinearGradient(0f, textSize / 2, width, textSize / 2, colors, null, Shader.TileMode.CLAMP)
paint.shader = textShader
}

fun Path.addParallelogram(
height: Int,
width: Int,
angle: Double,
cornerRad: Float = 0f
) {

val movePath = (height * tan(Math.toRadians(angle))).toFloat()

val topLeft = PointF(movePath, 0f)
val topRight = PointF(width.toFloat(), 0f)
val bottomRight = PointF(width.toFloat() - movePath, height.toFloat())
val bottomLeft = PointF(0f, height.toFloat())

val points = listOf(topLeft, topRight, bottomRight, bottomLeft, topLeft)

for (i in 0 until points.size - 1) {
val lineStart = getLineStart(points[i], points[i + 1], cornerRad)
val lineEnd = getLineEnd(points[i], points[i + 1], cornerRad)

if (i == 0) {
moveTo(lineStart.x, lineStart.y)
} else {
quadTo(points[i].x, points[i].y, lineStart.x, lineStart.y)
}

lineTo(lineEnd.x, lineEnd.y)
}

val topLineStart = getLineStart(topLeft, topRight, cornerRad)
quadTo(topLeft.x, topLeft.y, topLineStart.x, topLineStart.y)

close()
}

private fun getDist(p1: PointF, p2: PointF): Float = hypot(p1.x - p2.x, p1.y - p2.y)

private fun getLineStart(p1: PointF, p2: PointF, cornerRad: Float): PointF {
// above 0.5 means the corner rad is greater than half of the side. This means that two curves will
// intersect. To prevent that, we cap the ratio at 0.5
val radLengthRatio: Float = (cornerRad / getDist(p1, p2)).takeIf { it <= 0.5f } ?: 0.5f
return PointF(
(1.0f - radLengthRatio) * p1.x + radLengthRatio * p2.x,
(1.0f - radLengthRatio) * p1.y + radLengthRatio * p2.y
)
}

private fun getLineEnd(p1: PointF, p2: PointF, cornerRad: Float): PointF {
val radLengthRatio: Float = (cornerRad / getDist(p1, p2)).takeIf { it <= 0.5f } ?: 0.5f
return PointF(
radLengthRatio * p1.x + (1.0f - radLengthRatio) * p2.x,
radLengthRatio * p1.y + (1.0f - radLengthRatio) * p2.y
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ package club.cred.synth.internals

import android.graphics.BlurMaskFilter
import android.graphics.Canvas
import android.graphics.CornerPathEffect
import android.graphics.LinearGradient
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import android.graphics.Shader
import club.cred.synth.dp
import club.cred.synth.helper.addParallelogram
import kotlin.math.pow
import kotlin.math.sqrt

Expand Down Expand Up @@ -81,9 +84,16 @@ class BlurGradientHelper(
}
}

val path = Path()
val pathEffect = CornerPathEffect(NeuPlatformHelper.DEFAULT_PATH_RAD)

fun draw(canvas: Canvas, height: Int, width: Int) {
updatePaint(height, width)
rectArea.set(0f, 0f, width.toFloat(), height.toFloat())
canvas.drawRoundRect(rectArea, radius, radius, paint)
// rectArea.set(0f, 0f, width.toFloat(), height.toFloat())
// canvas.drawRoundRect(rectArea, radius, radius, paint)

path.reset()
path.addParallelogram(height, width, 10.0, cornerRad = NeuPlatformHelper.DEFAULT_PATH_RAD.dp)
canvas.drawPath(path, paint)
}
}
15 changes: 13 additions & 2 deletions synth/src/main/java/club/cred/synth/internals/BlurHelper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ package club.cred.synth.internals

import android.graphics.BlurMaskFilter
import android.graphics.Canvas
import android.graphics.CornerPathEffect
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import club.cred.synth.dp
import club.cred.synth.helper.addParallelogram

open class BlurHelper(
blur: Float,
Expand Down Expand Up @@ -62,15 +65,23 @@ open class BlurHelper(
}
}

val path = Path()
val pathEffect = CornerPathEffect(NeuPlatformHelper.DEFAULT_PATH_RAD)

fun draw(canvas: Canvas, height: Int, width: Int) {
val quickReject = if (!onlyBorder) {
canvas.quickReject(-blur, -blur, width + blur, height + blur, Canvas.EdgeType.AA)
} else {
canvas.quickReject(0f, 0f, width.toFloat(), height.toFloat(), Canvas.EdgeType.AA)
}
if (!quickReject) {
rectArea.set(0f, 0f, width.toFloat(), height.toFloat())
canvas.drawRoundRect(rectArea, radius, radius, paint)
// rectArea.set(0f, 0f, width.toFloat(), height.toFloat())
// canvas.drawRoundRect(rectArea, radius, radius, paint)

path.reset()
path.addParallelogram(height, width, 10.0, cornerRad = NeuPlatformHelper.DEFAULT_PATH_RAD.dp)
canvas.drawPath(path, paint)

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ package club.cred.synth.internals

import android.graphics.BlurMaskFilter
import android.graphics.Canvas
import android.graphics.Path
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.graphics.withTranslation
import club.cred.synth.SynthUtils.TYPE_ELEVATED_FLAT
import club.cred.synth.SynthUtils.TYPE_ELEVATED_SOFT
import club.cred.synth.appearances.NeuPlatformAppearance
import club.cred.synth.dp
import club.cred.synth.helper.addParallelogram
import club.cred.synth.helper.withClipOut
import kotlin.math.pow
import kotlin.math.sqrt
Expand Down Expand Up @@ -111,14 +113,24 @@ internal class NeuPlatformHelper(
return true
}

val path = Path()

fun draw(canvas: Canvas, height: Int, width: Int) {
val finalHeight = height + spread.toInt() * 2
val finalWidth = width + spread.toInt() * 2
val quickReject = canvas.quickReject(0f, 0f, finalWidth.toFloat(), finalHeight.toFloat(), Canvas.EdgeType.AA)
if (!quickReject) {
canvas.withTranslation(-spread, -spread) {
path.reset()
path.addParallelogram(
height = height,
width = width,
angle = 10.0,
cornerRad = DEFAULT_PATH_RAD.dp
)

// bg
withClipOut(clipOffset, clipOffset, finalWidth - clipOffset, finalHeight - clipOffset) {
withClipOut(path) {
withTranslation(shadowOffset / 2, shadowOffset / 2) {
darkShadow.draw(canvas, finalHeight, finalWidth)
}
Expand All @@ -138,5 +150,6 @@ internal class NeuPlatformHelper(
private const val DEFAULT_CORNER_RADIUS = 20
private const val DEFAULT_SHADOW_OFFSET = 12
private const val DEFAULT_SPREAD = 0f
val DEFAULT_PATH_RAD = 20f
}
}
45 changes: 45 additions & 0 deletions synth/src/main/java/club/cred/synth/views/ParallelogramLayout.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2020 Dreamplug Technologies Private Limited
* Licensed under the Apache License, Version 2.0 (the “License”);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/

package club.cred.synth.views

import android.content.Context
import android.graphics.Canvas
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import club.cred.synth.helper.addParallelogram
import club.cred.synth.internals.NeuPlatformHelper

class ParallelogramLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : FrameLayout(context, attrs, defStyleAttr) {

val cornerRad = NeuPlatformHelper.DEFAULT_PATH_RAD
var angle: Double = 10.0
val path = Path()

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
path.reset()
path.addParallelogram(h, w, angle, cornerRad)
}

override fun drawChild(canvas: Canvas, child: View, drawingTime: Long): Boolean {
val count = canvas.save()
canvas.clipPath(path)
val result = super.drawChild(canvas, child, drawingTime)
canvas.restoreToCount(count)
return result
}
}