I want to add a new View to a Layout dynamically by layout.addView(view) method. The new View is not supposed to be visible, but I want it's Display List to be created so it doesn't have to redraw (call onDraw method) itself when I decide to show it (by animation, for example fade in).
I run this code:
customView = new CustomView(this.getContext());
customView .setAlpha(0.0f);
this.addView(customView ); // 'this' is RelativeLayout instance in this case
onDraw method gets called for customView and everything is fine. However, when I change anything in my layout (push a button, scroll, anything that invalidates layout), the onDraw method for my customView is called second time. After that, it isn't called any more if I don't invalidate my customView (correct behaviour).
I don't know why Android behaves this way. I want it to create customView, call onDraw, create a Display List for it, and not call onDraw any more until I invalidate my view. To sum up, onDraw is supposed to be called once.
And it has nothing to do with initial invisibility of customView, if alpha is set to 0.5f, behaviour is the same.
My question is, how to make Android call onDraw only once?
And if Android really has to call onDraw twice, then what should I do to enforce it to do it in some code right after this.addView(view); without setting up any timers because THAT would be totally ugly.
The behavior you are describing is ok and is a part of the android framework for view object -
Drawing
Drawing is handled by walking the tree and rendering each view that
intersects the invalid region. Because the tree is traversed in-order,
this means that parents will draw before (i.e., behind) their
children, with siblings drawn in the order they appear in the tree. If
you set a background drawable for a View, then the View will draw it
for you before calling back to its onDraw() method. Note that the
framework will not draw views that are not in the invalid region. To
force a view to draw, call invalidate()
(Taken from the official google android API docs).
Meaning your custom view is contained by the same view that contains the button\scrollbar etc. If you don't want it to be rendered everytime the onDraw method is called for the subtree your view resides in you can set the view's boolean flag to false - use setWillNotDraw() to do that. (you should place it on the activity's onCreate in order to render the view set this flag to false (which is also the default) and use invalidate() whenever you want to render the view).You can read the official google docs for further information.
Related
I've read the documentation of this attribute:
An additional flag to be used with 'snap'. If set, the view will be snapped to its top and bottom margins, as opposed to the edges of the view itself.
https://developer.android.com/reference/com/google/android/material/appbar/AppBarLayout.LayoutParams.html#scroll_flag_snap
But I can't observe any actual effect in my app. What margin are they talking about? Every margin on the CollapsingToolbarLayout (on which this attribute is set) completely destroys the layout.
Not sure if it's useful yet, but here is the difference:)
If you pass snap as scroll flag, then it will move your view (in my case this search bar, it's linearLayout) to it's edge NOT INCLUDING the margin_layout
Then I've tried snap|snapMargin and it moved with the margin
P.S. No idea why snapMargin doesn't work without snap ¯\_(ツ)_/¯
This attribute is responsible for a scrolling behavior of AppBarLayout and its children. You can apply it directly to AppBarLayout or on the inside views, in the xml layout of your AppCompatActivity. It has to be an instance of AppCompatActivity if you want to use AppBar features. Also, the design library must be included in Gradle dependencies, like so: implementation 'com.android.support:design:26.1.0'
Please refer this link:-[https://medium.com/#tonia.tkachuk/appbarlayout-scroll-behavior-with-layout-scrollflags-2eec41b4366b][1]
I am using 'com.android.support.constraint:constraint-layout:2.0.0-alpha5'.
I have a fragment using MotionLayout inside an activity that also carries a BottomNavigationView inside a CoordinatorLayout with a custom behaviour allowing to show and hide when the content is scrolled.
With all fragments, where there is no MotionLayout, this behaviour works perfectly. Only with the MotionLayout, which has a NestedScrollView as a child, and makes use of an onSwipe transition, this swipe seems to be consumed, and does not arrive at the activity's coordinator layout.
Is this a current limitation of how MotionLayout works, and is it possible to extend it to support my use case?
I want to know how to move a view from top to bottom continuously without animation. I am asking this because I want to get the position of the view at every step so that I can check that if there is any collision between that view and any other view.
With animation you can move (not exactly move) a view from one position to another position (Animator class), but animation produces an illusion to the user that it is moving but it's position is fixed all the time. So this can't be done using animation?
Second approach is incrementing position of view. I applied this method in onCreate(). If I used it without Thread.sleep(50) then the activity doesn't show the view, if I applied it with Thread.sleep(50) then activity doesn't start for some period.
Property animation (subclasses of Animator class) actually move the view, as they update the actual property of the view. It is the view animations (subclasses of Animation class) that don't move the actual view and instead just where it appears to the user.
Source:http://developer.android.com/guide/topics/graphics/prop-animation.html
Quote: With the property animation system, these constraints are completely removed, and you can animate any property of any object (Views and non-Views) and the object itself is actually modified.
You also shouldn't start moving things around in the onCreate method as things are still initializing (onwindowfocuschanged is recommened). Also if you call thread.sleep, you are going the sleep the main UI thread, hence freezing the application for a time.
Solved the problem using ValueAnimator :-
CodeSnippet :-
va=ValueAnimator.ofFloat(0.0f,size.y);
va.setDuration(5000);
va.setRepeatCount(va.INFINITE);
va.setRepeatMode(va.REVERSE);
va.start();
va.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
// TODO Auto-generated method stub
bullet[0].setTranslationY((Float) va.getAnimatedValue());
Rect R11=new Rect(bullet[0].getLeft(),bullet[0].getTop()+(int)bullet[0].getTranslationY(),bullet[0].getRight(),bullet[0].getBottom()+(int)bullet[0].getTranslationY());
Rect R21=new Rect(ball.getLeft(), ball.getTop(), ball.getRight(), ball.getBottom());
if(R11.intersect(R21))
va.cancel();
}
});
I'm facing a problem with the LWUIT's Textfield.
In some of my Forms I display a CategoryBar, while in others I hide it.
In some of the Forms I have Textfields, the problem presents itself when I focus on one and make the Virtual Keyboard (VKB) to appear. When the VKB appears, the screen components resize themselves to adjust to the Textfield to be visible while text is entered, but when I hide the VKB, either through the back button or the return key on the VKB, the Textfield remains with the focus, not only that, when the screen components resize themselves, the current visible Form resizes itself as if there was no CategoryBar present, so any components that are at the bottom of the Form are hidden by the CategoryBar.
This is fixed by displaying another Form (this includes PopupChoiceGroup and DatePicker) and then going back to the Form that is covered by the CategoryBar.
In other Forms where no CategoryBar is visible, sometimes the resizing when the VKB is shown causes the Forms to resize themselves as if the CategoryBar was visible, making it possible to interact with it when it shouldn't be available.
How can I make sure the focus is completely lost on the Textfield? Also, how to make sure a Form is resized correctly whether a CategoryBar is visible or not?
EDIT
I've been digging through the class reference for TextField, Form and VKB, in the later I found a method called autoAdjust which according to documentation:
Auto adjust size of the dialog. This method is triggered from a
sizeChanged event.
The method sizeChanged sounded like something I should check and in the Form's reference the description for this method is:
This method is only invoked when the underlying canvas for the form
gets a size changed event. This method will trigger a relayout of the
Form. This method will get the callback only if this Form is the
Current Form
This method seemed like the callback for resizing I was looking for, so I overrode it and placed a NotificatioBar to be displayed with the width and height values sent when the method was called.
What I found after testing this on my device was that when the Form was being resized after the VKB was shown or hidden, the height value sometimes instead of being 270 (the height for the Form when the CategoryBar is being displayed) it was sent as 320 (the full screen height, as if no CategoryBar was being displayed).
So far I haven't been able to understand why would the Form ignores the fact that the CategoryBar is being displayed or not when resizing the itself.
I tried to change the Form height inside its sizeChanged method but the Form wasn't affected by it. It seems to me what I have to modify is the canvas where the Form is being drawn, but I don't really know for sure since the canvas is hidden in LWUIT.
Could it be the canvas where my Form is being drawn is the one at fault? What is provoking this behaviour?
At the moment I found a workaround to avoid having my Components hidden by the CategoyBar because the Form resized wrongly after the VKB hid, for the scenario in which the Form resizes wrongly and displays the CategoryBar (which I don't know why is visible if I'm calling to its setVisibility method and passing false).
First I overrode the sizeChanged method:
protected void sizeChanged(int w, int h){
if(h > 270){
mainContainer.getStyle().setMargin(Component.BOTTOM, 50);
}
else{
mainContainer.getStyle().setMargin(Component.BOTTOM, 0);
}
}
I check the height value, if the value is greater than the expected height when the CategoryBar is being displayed then I set the bottom of my Container to 50, so it'll be visible.
But this wasn't enough because if I show again the same form and it resizes correctly then the Container will remain with a bottom of 50. So I overrode the onShow method too:
protected void onShow(){
int containerBottom = mainContainer.getStyle().getMargin(Component.BOTTOM);
if(this.getHeight() == 270 && containerBottom == 50){
mainContainer.getStyle().setMargin(Component.BOTTOM, 0);
}
}
I had to make sure if the height was 270 and my Container's bottom was 50 then the Container's bottom should be 0.
Since I haven't found a way to avoid having my Form to resize and show the CategoryBar when it shouldn't be displayed at all, I don't consider myself with a full answer. Will update if I find a workaround for this.
EDIT
I tried with explicitly setting the shown/hidden status by calling the setVisibility method inside the onShow method of every Form I have. So far I've been able to avoid the visual problems I experienced previously. I'm not sure if this problem was due to LWUIT or due to J2ME restrictions but this is how I worked around it.
i am new to GWT and GWTP and the question sounds stupid.. Can I make an abstract PresenterWidget or similiar?
Like in normal Java extending the "class" and reuse / extend the logic. But not only the class, the whole thing of View and Presenter. I try to explain my initial situation and maybe you have another idea.
The image hopefully helps to explain it. The "Main-Tab" and every other tab consists of a collection of views which have the same base structure and the same logic.
the base structure consists of
border around EVERYTHING
an image (the wwitch)
a title
a textarea
a PresenterWidget which is added to a contentSlot of the parent (the menu left)
and below the base are view specific components like buttons, text or any other widget. So a main part of the view with logic is repeading. If the switch is "toggled" the view is hidden (the textarea and any childs / view specific components) like the lowest view in the picture. Furthermore the PresenterWidget left changes the color.
The logic is working, but now I am searching a proper way to solve this without repeading code and the possibility to add child elements which are hidden as well by toggling the switch. Can I add to a PresenterWidget child widgets and define where there should be added? like: Even if this is possible, it feels a bit inconvenient.
Thanks in advance.
I just want to post the solution:
I have now a simple Composite (KPICommonView) for the switch, title and the description. It got another FlowPanel below the description, where the specific components will be added later. For this the Composite implements "HasWidgets" and overrides the "add(Widget w)"-method which is called by UiBinder if the Widget is added and has child elements.
<own:KPICommonView title="First Header" description="I am a happy description :)" anchorToken="{nameAnchors.getFirst}">
<g:Label>child component</g:Label>
</own:KPICommonView>
I am not sure if I do a PresenterWidget for every segment and every PresenterWidget has one of the KPICommonView added, or if I do one normal Presenter which adds more than one of the CommonViews.
The CommonView furhter creates the PresenterWidget for the menu item on the side. It gets the attributes from the constructor (anchorToken, title) and adds it to the slot (which happens ugly, because the View has hard coded the parent saved to call "addInSlot()". The repeading code for the switch is handled by the KPICommonView.