Rendering ViewGroup on Canvas - android

I'm implementing a small library for easy adding custom view swiping actions on a RecyclerView. During my implementation I've hit a issue when rendering views on a canvas. I've attached a gif here to showcase the problem:
When drawing the swipe view on the Canvas I do the follow:
private fun renderSwipeView(
view: View,
c: Canvas,
width: Int,
height: Int,
transX: Float,
transY: Float
) {
view.measure(
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
)
view.layout(0, 0, width, height)
c.withTranslation(transX, transY) {
view.draw(c)
}
}
This generally works fine, but I'm seeing issues rendering with view types. In the GIF i
The green layout is a square which is centered to the top of the layout. So I know the layout is rendered in the correct size and the layouting of elements is done correctly.
Issue 1:
The blue boxes are TextView's with singleLine=true since I want the text to be neatly revealed by the element on top. Swipe right basically works fine, however on swipe left the text is not rendered at all. I tried to render this same case without rending it on a Canvas which works fine. Am I missing some part when rendering my view on the canvas?
Issue 2:
Not really a big problem, but the swipe view (red / orange container) will be rendered out side it's layout. I could easily fix this by using canvas.clipRect() on the canvas, but I would like to solve the root cause of this rather than do a workaround.
Entire source code with this demo can be seen here.
Thanks
Best regards

Regarding issue 1: I just managed to first issue. It seems to be related to a bug in TextView, by switching to AppCompatTextView the issue was solved.

Related

Custom View with LAYER_TYPE_SOFTWARE clips view

I've created a custom view which extends TextView. I want to use a BlurMaskFilter on an oval, however, unless I use LAYER_TYPE_SOFTWARE, the oval isn't blurred as expected. Using LAYER_TYPE_SOFTWARE will blur the view correctly, however now it is clipped to its bounds which I want to avoid as I am trying to create a colored shadow effect.
Bizarrely I only have this issue on API's 21-27 (min API is 21). On API's 28+ BlurMaskFilter works correctly with hardware acceleration and also has no issues drawing outside the view bounds.
LAYER_TYPE_HARDWARE
LAYER_TYPE_SOFTWARE
LAYER_TYPE_HARDWARE API 28+ (Desired effect)
I've tried setting clipChildren=false on all the views in the hierarchy, with no luck.
I also tried increasing the canvas.clipRect using negative values as per this post: https://stackoverflow.com/a/15506277/5752426 however this only seemed to work when using positive values to decrease the drawing area, and had no effect when using negative values to draw outside the view bounds.
I can somewhat get around the issue by increasing the view bounds in onMeasure() and then only painting inside those view bounds, however, this isn't ideal as I now have to account for this extra space when positioning my views in the layouts. Furthermore, the problem becomes inconsistent to account for as different views might have different elevations and shadow/blur sizes.
init block for the custom view:
init {
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
setWillNotDraw(false)
...
onDraw for the custom view:
override fun onDraw(canvas: Canvas?) {
...
if (elevation > 0f) {
circleShadowBackgroundPaint.maskFilter = circleBlurMaskFilter
canvas?.drawOval(circleBlurBackground, circleShadowBackgroundPaint)
}
...
Any help would be appreciated!
If you set this View's LayerType to LAYER_TYPE_SOFTWARE,the clipCHildren and clipToPadding will no longer has anly effect on this View.You should setLayerType on its Parent(or parent's parent ,if the parent is as large as the size of this View).
You can try (View (getParent())).setLayerType(View.LAYER_TYPE_SOFTWARE, null)

Android: Zooming EditText Android Issue in translation And Getting Touch event of childView when Placed outside parentView

my question is related to android feature to zoom the parent consisting of multiple child view's.
ZoomView->ParentView->[multiple childViews]
I am working on a Demo project to Zoom the child View and to pan infinitely.Zooming works perfectly as needed.
PROBLEM 1:
But if there is a EditText in the view and i try to zoom on that then below issues are faced by me.
on zooming in the text is blurred
pointing on a text is working fine but translating through the text is
translating very fast as its translation is multiplied by the
scalingFactor
Selecting the text is also having above issue.
Try running the the Demo to understand the issue if not clear from above
I have tried two approaches to Zoom the content of the View but both approaches gave the same issue.
Scaling canvas and transforming the MotionEvent by scaling the MotionEvent by Matrix.class of the Parent Class.
Setting ScaleX and ScaleY of the Parent containing the childViews
hierarchy of my demo project zooming the view(UML Diagram)
Basic problem is placing the cursor at the right position when the view is scaled to some value.
I have already referred to this thread
PROBLEM 2:
if i have a childView which is movable in the parent View then after zooming out if the childView is translated outside the bounds of parentView the events are ceased to capture and the child view becomes untouchable
i have tried using TouchDelegate but i don't know how to expand the parentView touch area .Code reference Thread
scale is 1 the area touch area is equal to screen for parentView and ZoomView
But when scale factor is not equal to one the touch area of parent is lesser(zoomIn) than the ZoomView as displayed
Yellow-parentView Touch Region
Cyan-ZoomView Touch Region
Green-ChildView Touch Region
ScreenShot here
Note:
This is my first Question on StackOverflow So please recommend if some edits are needed.
This the the closest i got to solve above problem's.
PROBLEM 1:
On zooming in the text is blurred
setLayerType(LAYER_TYPE_HARDWARE,null);
set layer type Hardware in the view which has text View. for me i
set it in green square view.
pointing on a text is working fine but translating through the text is translating very fast as its translation is multiplied by the scalingFactor
Selecting the text is also having above issue.
For above two:
This is a bug in android when you scale a view using the scaleX,scaleY api's the EditText get's event based on the current scale value of parent's.But issue is with the Cursor of editText.
The best solution we got is we wrote our own EditTextView (which extend's TextView).As we checked android framework source code we came to know that android use's PopUpWindow to display cursor on screen.
The source of issue is when we use scaleX and scaleY editText get's scaled even't as it's parent is scaled but as cursor is a PopUpWindow and not a child of EditText so event's are not scaled and above issue occur's
So wrote our own EditText if you see the source code EditText code is not very complex and can be written on our own.And to solve the scaling issue of Cursor, we added our own Cursor PopUpWindow and made it Scale aware.
NOTE:
(UPDATE)
Check at demo code here customEditText and CustomCursor.
Run the project set focus pink focus(BY Android) will come ,wait for few seconds then the black cursor will appear that is the custom cursor.
It is a very basic example and we need to add all other edit text Feature's on our own like multi-Select, popUpMenu etc.
PROBLEM 2: if i have a childView which is movable in the parent View then after zooming out if the childView is translated outside the bounds of parentView the events are ceased to capture and the child view becomes untouchable i have tried using TouchDelegate but i don't know how to expand the parentView touch area
This solution is specific to the given problem not a generic one
as there can be multiple solution's for this problem.
In this case 3 view's are there:
Yellow-parentView of green square View
Cyan-parent of yellow View
Green-ChildView non touchable outside parent
My Solution is that i used created a callback from green square view to Yellow parent view. Whenever the translation of green square view ended the callback is triggered and in yellow parent i used below code.
override fun eventEnded() {
setDelegate()
}
fun setDelegate() {
val rect = Rect()
val parent = (this.parent as View)
parent.getHitRect(rect)
val touchDelegate = TouchDelegate(rect, this)
if (View::class.java.isInstance(editorContainer.parent)) {
(editorContainer.parent as View).touchDelegate = touchDelegate
}
}
The above code translate to : when child view translation is ended check the bound's of parent and update the TouchDelegate accordingly.
As the problem i faced was when i scaled(Zoomed) the view then the View's delegate was not updated so for that also solution is same make a callback from zoomView (parent) to yellowView (childView) onScaleEnded call setDelegate().
When scale changes the hitArea also changes but as per delegate nothing is changed so we need to update the rect of TouchDelegate.
Please feel free to discuss in comment section. If someone has a better solution Really eager to know.As we tried many different solution's but nothing else worked.This is the best i found and i am using above code in production and haven't faced any issue till now.
The best approach for translating and scaling EditText is to use scaleX, scaleY, translateX, translateY on this particular EditText instead of parent layout canvas translation.
e.g. in kotlin
editText.scaleX = scaleFactor
editText.scaleY = scaleFactor
editText.translateX = offsetLeft
editText.translateŠ½ = offsetTop
By the way, it is possible to check if touch area and drawing area are the same in android studio using Tools -> Layout Inspector.

Redrawing clipped content in Android View after moving into bounds

Within Android, I'm trying to move a TextView from outside the parents bounds into view, but the contents never shows up, or remains clipped if it was partially within the bounds already.
Initial situation at start
Situation after animation
(Below this is another view, that was completely out of bounds and isn't drawn either)
I have 4 TextViews below each other in a custom Object extending RelativeLayout. Based on a percentage the top 2 should move outside it's bounds and the bottom 2 should move in (from the bottom).
I use the following code to update the properties of each TextView. In this class each variable **positionY* is filled with their initial position from the layout-xml. effect is percentage between 0 & 1. The animation works, but the views aren't drawn again.
public class ActionBarTitleView extends RelativeLayout {
public void updateTransition(float effect) {
float height = getHeight();
titleView1.setY(title1positionY - height*effect);
detailView1.setY(detail1positionY - height*effect);
titleView2.setY(title2positionY - height*effect);
detailView2.setY(detail2positionY - height*effect);
invalidate();
}
}
What I tried
After some researching I found a few hints what the issue might be, but so far none of the tried options had any effect. Below is a list of things I've found on SO and tried.
Calling invalidate() on the RelativeLayout - No effect.
Invalditing the TextViews - No effect.
clipChildren = false for the RelativeLayout - No effect.
setWillNotDraw = false for the RelativeLayout - No effect. (onDraw is being called)
I haven't tried to solve this with a ScrollView, but I don't want to really, cause that adds another layer in the hierachy for something pretty small.
I thought I understood the drawing logic, but perhaps I'm missing something, so I hope someone might be able to point me in the right direction.
What I ended up doing (September 3rd)
Since no real solution was offered, I tried again and came to the following "fix". I set both second labels to Visibility.GONE, but within the original bounds of the container view. Then when I start the animation, I set their correct values, then move them outside the bounds and finally setting Visiblity.VISIBLE. When the animation progresses the labels roll into view as supposed to. So a fix to the issue, but no real explanation why the TextViews aren't drawn again...

How to scale ViewGroup and its child views with good performance

I am implementing stuff like YouTube App which you can drag the video window to the lower right corner.
I am able to achieve the same effect using setLayoutParam(), but it turns out not as fast as I expected (as smooth as YouTube).
So I use setScaleX and setScaleY instead. It's fast and the behavior is similar to YouTube app. But the scale seems not applied to the child views.
So, what can I do to efficiently scale a ViewGroup and it's child views. Thanks.
layout.xml:
<ScalableRelativeLayout android:id="#+id/parent" >
<VideoView android:id="#+id/video"/>
</ScalableRelativeLayout>
When the parent get scaled, the video seems not scaled and only shows part of it. I guess the parent scale didn't pass to its children, so I override below method.
Override method:
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save();
canvas.scale(mScale, mScale);
super.dispatchDraw(canvas);
canvas.restore();
}
ScalableRelativeLayout extends RelativeLayout and override above method. Now the video scale inside parent, only occupy upper-left area.
It seems the video content will not affected by the view.

Antialias the view being transformed

I am transforming child views in my viewgroup when I'm swiping through the viewgroup (kind of a cover-flow effect). I am using matrix.setPolyToPoly for transformation. The views have borders which need antialiasing severely.
So far I've tried to use
canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG));
in my children's onDraw, but it doesn't seem to change anything. Also, I'm aware of BitmapDrawable.setAntiAlias(true), but my children are not drawables, but full-blown viewgroups with views inside, so I cannot use that.
Override
protected void dispatchDraw(Canvas canvas)
in your custom layout and set filter there.
canvas.setDrawFilter(new PaintFlagsDrawFilter(1, Paint.ANTI_ALIAS_FLAG));
super.dispatchDraw(canvas);
I encountered a similar issue in my cover flow inspired Gallery. This solved my issue.

Categories

Resources