I want to create a layout with animation curved lines like this link:
https://cdn.dribbble.com/users/1032798/screenshots/4981336/untitled-1.gif?vid=1
I would go with a custom view and draw my own path
class DrawView : View {
...
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
path = Path()
paint.color = Color.RED
paint.strokeWidth = 3f
path.moveTo(34f, 259f)
path.cubicTo(68f, 151f, 286f, 350f, 336f, 252f)
canvas.drawPath(path!!, paint!!)
}
}
This ends up into
Now you have to make this parameterize, to make it animate-able.
To do so, it's quite easy to use a MotionLayout
Here is the code
Related
How can I create pie chart using onDraw override method in Kotlin on Android? I've tested multiple method Paint.apply parameters but didnt achieve pie chart. My code so far looks like this:
class ChartView(context: Context, attrs: AttributeSet) : View(context, attrs){
val paint = Paint().apply {
color = Color.GREEN
style = Paint.Style.FILL
}
val text = "My Component"
val bounds = Rect().also {
paint.getTextBounds(text, 0, text.length, it)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawCircle(344F, 890F, 160.0F,paint)
}
}
This resulted in regular green circle. Target effect would be:
https://ibb.co/Vw9Lzc0
I have built a custom view class called progressCircle which is a snapchat-like, circular progress bar - this is inside a constraint layout, over a circular button.
This view has parameter angle which when called from onViewCreated(), will work perfectly if run
progressCircle.angle = 100f
However, I am trying to animate this onClick. If I run this same code, onClick, the progressCircle will not show up?! After trial and error, I found that updating the background colour here made the view visible & it was updated. IE;
button.setOnClickListener {
progressCircle.setBackgroundColor(android.R.color.transparent)
progressCircle.angle = 270f
}
Whats going on here, and how can I fix this so I can animate it properly...
Edit:
class ProgressCircle(context: Context, attrs: AttributeSet) : View(context, attrs) {
private val paint: Paint
private val rect: RectF
private val fillPaint: Paint
private val fillRect: RectF
var angle: Float
var startAngle: Float = 0f
init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressCircle)
angle = typedArray.getFloat(R.styleable.ProgressCircle_angle, 0f)
typedArray.recycle()
val offsetAngle = 0f
val color = getColor(context, R.color.outputON)
val strokeWidth = 15f
val circleSize = 276f
paint = Paint().apply {
setAntiAlias(true)
setStyle(Paint.Style.STROKE)
setStrokeWidth(strokeWidth)
setColor(color)
}
rect = RectF(
strokeWidth,
strokeWidth,
(circleSize - strokeWidth),
(circleSize - strokeWidth)
)
fillPaint = Paint().apply {
setAntiAlias(true)
setStyle(Paint.Style.FILL)
setColor(getColor(context, R.color.flat_blue_1))
}
val offsetFill = strokeWidth
fillRect = RectF(
offsetFill,
offsetFill,
(circleSize - offsetFill),
(circleSize - offsetFill)
)
//Initial Angle (optional, it can be zero)
angle = offsetAngle
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
if (getColor(context, R.color.flat_blue_1) > 0) {
canvas.drawArc(rect, 0f, 360f, false, fillPaint)
}
canvas.drawArc(rect, startAngle, angle, false, paint)
}
}
TIA
By default, a View only redraws itself when something has changed - i.e., when the view is "invalidated" as per the View documentation:
Drawing is handled by walking the tree and recording the drawing commands of any View that needs to update. After this, the drawing commands of the entire tree are issued to screen, clipped to the newly damaged area.
If you want your custom view to redraw itself when the angle property is changed, you need to call invalidate():
var angle: Float
set(value) {
// Do the default behavior of setting the value
field = value
// Then call invalidate() to force a redraw
invalidate()
}
}
In an Android app I have an object that is created through a custom view. It basically has a rectangular shape. I want to apply a 3D transformation that makes it look like this:
In the draw() function I have tried various things like this:
override fun draw(canvas: Canvas?) {
super.draw(canvas)
val matrix = Matrix()
var pivX = myWidth / 2.0f
var pivY = myHeight /1.0f
matrix.setSkew(1f, 0f, pivX, pivY);
canvas?.withMatrix(matrix) {
drawPath(path(-150F), paint())
drawPath(path(150F), paint())
}
}
I couldn't make it work though. Where's my mistake? What am I missing?
So I'm trying to draw a rectangle in kotlin and I have a class that does this but I need the size of the canvas to do this so in my main view I call the classes setCanvas() function in my onDraw() function, something like this.
main view
var rectangle = Rectangle()
override fun onDraw(canvas:Canvas) {
super.onDraw(canvas)
rectangle.setNewCanvas(canvas)
rectangle.show()
rectangle.update()
invalidate()
}
class
class Rectangle {
private var canvas: Canvas? = null
var x = 0
var speed = 10
fun setNewCanvas(newCanvas: Canvas)
if(canvas == null) {
canvas = newCanvas
x = canvas?.width!!
}
}
fun show() {
canvas?.drawRect(x.toFloat(), 0F, x.toFloat() - 100, 1000F, Paint(Color.RED))
}
fun update() {
x -= speed
}
}
I'm trying to get the rectangle to move across the screen but when I check if canvas is null in setNewCanvas() it moves but the rectangle is drawn above the canvas in the banner where the apps project name is. If I don't check if canvas is null then the value of x gets reassigned to the width with every call so the rectangle never moves.
I think you should not encapsulate the function of modifying coordinates into Rectangle, and you cannot set canvas repeatedly.
var x = 0
var speed = 10
fun update() {
x -= speed
}
override fun onDraw(canvas:Canvas) {
canvas.drawRect(x.toFloat(), 0F, x.toFloat() - 100, 1000F, Paint(Color.RED))
rectangle.update()
invalidate()
}
Nothing is being drawn, even tho function is called.
I tried:
1. Moving super.onDraw(canvas) to beginning and end of onDraw
2. Replacing it with draw(canvas)
3. Creating my view dynamically and statically (I mean, in XML)
4. Adding setWillNotDraw(false)
class GameView(context: Context) : View(context) {
init {
setWillNotDraw(false) // doesn't change anything
setBackgroundColor( Color.DKGRAY ) // this actually works, but onDraw is not, why?
}
private val ballPaint = Paint(ANTI_ALIAS_FLAG).apply {
color = 0xfefefe
style = Paint.Style.FILL
}
override fun onDraw(canvas: Canvas?) {
println("Test") // printed!
canvas!!.apply {
drawCircle((width/2).toFloat(), (height/2).toFloat(), 100.0f, ballPaint )
}
super.onDraw(canvas)
}
}
What am I doing wrong?
Thanks to pskink, that was the problem
color = 0xfffefefe.toInt()