Issue
My current Android Application UI requires a two tone background with a curved arc as border as shown in the following image
I can achieve this effect in portrait (although I do not like using negative margin values) as follows...
<ImageView
android:id="@+id/backgroud_arc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="-150dp"
android:layout_marginEnd="-150dp"
android:adjustViewBounds="true"
android:scaleType="centerCrop"
android:src="@drawable/background_circle" />
where background circle is this drawable shape
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/background" />
<size
android:width="120dp"
android:height="60dp" />
<corners
android:bottomLeftRadius="60dp"
android:bottomRightRadius="60dp" />
</shape>
Is there an easier method I can employ to achieve the desired effect?
In landscape this drawable is very badly "clipped".
Solution
Instead of using an inflexible drawable background, we should rather draw the colours along with the curve on the canvas.
For this we create a custom View ArcBackgroundView
as below. The code is self explanatory:
import android.content.Context
import android.content.res.Configuration
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
class ArcBackgroundView(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val paint = Paint()
private val path = Path()
init {
paint.isAntiAlias = true
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas == null) {
return
}
// Draw background color
canvas.drawColor(ContextCompat.getColor(context, R.color.blue))
// Draw curve portion of background
// Setup color
paint.color = ContextCompat.getColor(context, R.color.white)
val curveStartAndEndY = 0.6f * measuredHeight // <------ You can change this value based on your requirement
// Set curve's control point's Y position (downwards bulge of curve) based on orientation
var curveControlPointY = measuredHeight / 1.4f // <------ You can change this value based on your requirement
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Since in landscape mode, the curve will have greater arc length,
// we need to give the curve more downwards bulge as compared to that in portrait mode.
curveControlPointY = measuredHeight / 1.2f // <------ You can change this value based on your requirement
}
// Now we draw the entire path for curve
path.moveTo(0f, curveStartAndEndY)
path.quadTo(
measuredWidth / 2f,
curveControlPointY,
measuredWidth.toFloat(),
curveStartAndEndY
)
path.lineTo(measuredWidth.toFloat(), 0f)
path.lineTo(0f, 0f)
path.lineTo(0f, curveStartAndEndY)
canvas.drawPath(path, paint)
}
}
The ArcBackgroundView
can now be used in an xml as shown below:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.myapp.ArcBackgroundView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
The resulting output for Portrait and landscape is shown below:
Apart from creating a custom view as shown, if you require, you can also create a say custom FrameLayout
called ArcBackgroundFrameLayout
. Copy paste the code of onDraw() into your ArcBackgroundFrameLayout's
onDraw()
. Now you can use your custom container directly like below:
<?xml version="1.0" encoding="utf-8"?>
<com.example.myapp.ArcBackgroundFrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/teal_200"
android:gravity="center"
android:text="THIS IS A TEXT VIEW ON TOP OF THE DUAL TONE BACKGROUND"
android:textSize="28sp"
android:textStyle="bold" />
</com.example.myapp.ArcBackgroundFrameLayout>
Note the android:background="@color/black"
added with the ArcBackgroundFrameLayout
. Some background (not necessarily black color) must be added otherwise for containers, #onDraw() would not be called. You should not worry about this black color as it would not show. We are changing background colours from inside our overridden onDraw()
.
The resulting output for Portrait and landscape is shown below:
If you have any other requirement, please let me know. I will edit this answer.
The code is in Kotlin. If your project is in Java, please let me know again. I can edit and give a Java version of the same.
Thanks.
Answered By - karan gupta
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.