I have a custom viewstack that applies automatically a slide in/slide out effect when the view changes. Everything goes smoothly when the views are lightweight but becomes jumpy when the next view requires heavy rendering.
Here are the relevant parts of the code :
_showEffect = new Parallel();
_contentMove = new Move();
_imageMove = new Move();
_showEffect.addChild(_contentMove);
_showEffect.addChild(_imageMove);
_showEffect.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);
I apply the parallel effect to the showEffect of every view :
vis.setStyle("showEffect", _showEffect);
I define the property of the moves depending on the direction of the animation, here to the left (where _views is my resident viewstack in the custom component) :
_contentMove.xFrom = _views.width;
_contentMove.xTo = 0;
_contentMove.yFrom = 0;
_contentMove.yTo = 0;
_imageMove.xFrom = 0;
_imageMove.xTo = -_views.width;
_imageMove.yFrom = 0;
_imageMove.yTo = 0;
_imageMove moves a screen image of the previous view which is set to visible when the animation starts and hidden when it ends.
I have tried some hacks like lengthening the duration of the animation when the next page has never been shown before but this is not quite generic as the required duration to have a smooth transition changes depending on the rendering requirements.
Isn't there any way like in other programming languages to force the layout/rendering process of the next page while it is still out of view ?
Thanks
Viewstack has a creationPolicy property. By default this is set to ContainerCreationPolicy.AUTO, which means the views are rendered as-needed. This explains why the view appears jumpy when switching to it. You can set the creationPolicy property to ContainerCreationPolicy.ALL and it will force the ViewStack to prerender all of its views before they are loaded.
This will solve your problem but note that it will increase overall initialization time of your application because it will now be forced to render everything ahead of time.
Related
I have an Exoplayer view in a fragment, when I animate the fragment container view from the activity the exo player will become black. I used setKeepContentOnPlayerReset(true); to keep the last frame and it's working fine. But when I call the animate (sliding animation) on fragment container view (that's a Frame Layout) after the video is over, Exo player will display the black screen. (even the fragment exit transition also creates the same issue on Exo player, this time I didn't replaced the fragment just animated the container view, the issue is still present) I haven't any clue related to this issue, It would be very helpful if anyone can share some idea related to this. welcomes every suggestion and answers related to this. Thank you.
It's turned out that using "texture_view" for "app:surface_type" will resolve the issue, This will make the Exo player use texture view instead of the surface view and that makes animations and scrolling smooth.
In documentation its says
On earlier releases, this could result in unwanted effects when a
SurfaceView was placed into a scrolling container, or when it was
subjected to animation. Such effects included the SurfaceView’s
contents appearing to lag slightly behind where it should be
displayed, and the view turning black when subjected to animation
In xml file, we can enable texture view as follows
<com.google.android.exoplayer2.ui.SimpleExoPlayerView
android:id="#+id/playerView"
android:layout_width="match_parent"
android:layout_height="200dp"
app:surface_type="texture_view"/>
You can use this 2 solutions...
add this attribute to PlayerView :
app:surface_type="texture_view"
use this in your code :
val simpleExoPlayer = SimpleExoPlayer.Builder(requireContext())
.setMediaSourceFactory(
DefaultMediaSourceFactory(requireContext())
)
.build()
simpleExoPlayer.addAnalyticsListener(object : AnalyticsListener {
override fun onSurfaceSizeChanged(
eventTime: AnalyticsListener.EventTime,
width: Int,
height: Int
) {
super.onSurfaceSizeChanged(eventTime, width, height)
val surfaceView = playerView.videoSurfaceView
if (surfaceView is SurfaceView) {
surfaceView.holder.setFixedSize(width, height)
}
}
})
Interface Builder in XCode 4.5 respects the intrinsicContentSize for some views, e.g. NSButton, but I can't convince it to respect it on my own custom subviews. This causes IB to add extra constraints trying to force the layout drawn in IB, which then causes the intrinsic sizes to not be used when the program is run.
For example, consider a button centered in a window, and a custom view centered in a window…
You can see that the custom view gets four constraints, presumably because IB doesn't know the view's intrinsicContentSize. You can change which extra constraints are added, e.g. you can force it to be width and height instead, but you can't delete them.
I'm coping with this now by searching and deleting the extra constraints in my awakeFromNib, but there must be a better way to do this.
Set a placeholder intrinsic content size — a "guess," if you will — in Interface Builder.
Select your custom view.
Show the size inspector (⌘Shift5).
Change the "Intrinsic Size" drop-down from "Default (System Defined)" to "Placeholder."
Enter reasonable guesses at your view's runtime width and height.
These constraints are removed at compile-time, meaning they will have no effect on your running app, and the layout engine will add constraints as appropriate at runtime to respect your view's intrinsicContentSize.
How to actually do this, 2019
import UIKit
#IBDesignable class TagPerson: ShadowRoundedImageView {
override var intrinsicContentSize: CGSize {
var s = super.intrinsicContentSize
s.height = 40
s.width = 40
return s
}
override func prepareForInterfaceBuilder() {
invalidateIntrinsicContentSize()
}
}
However, there is a problem. Xcode is buggy. You can sometimes reset it by:
The above will of course work flawlessly at runtime. But it randomly fails to work in interface builder (even with 11+).
To make it cycle, try
The usual 'Refresh all views'
Attach and delete a pointless constraint to one of your intrinsic size views. (I've noticed if you have a number of them, doing this to one is usually enough to make Xcode cycle, then they all work.)
And finally:
Xcode has an "intrinsic size placeholder" feature.
Select one or more of your intrinsic-size elements. Toggle the bizarre placeholder thing back and fore a few times. Often that makes it cycle and the view will then work correctly.
At worst, restarting Xcode with the usual clean-everything will, sometimes, get it working.
Ok, the point here is to make Xcode use the intrinsicContentSize of your custom view in IB.
This can be achieved by adding a placeholder view inside your custom view in IB with a fixed width and height (you can center it horizontally and vertically as well)
Then select your custom view and tap "Size To Fit Content" form the Edit Menu in IB.
At this point all extra size defining constraints will be deletable leaving only positioning ones.
That way IB will size your custom view to fit the placeholder view and and Autolayout would depend on your view's override of - (CGSize)intrinsicContentSize in run time to determine your custom view's size.
Last step is to delete the placeholder view to allow your view to display its content and size correctly:
- (void)viewDidLoad
{
[super viewDidLoad];
[_placeholderView removeFromSuperview];
}
I know this is a hack but hopefully it helps you.
I am trying to implement a calendar using UICollectionView which has a similar scrolling behaviour to the built in calendar app when changing months. At the moment the view is flickering as the resize occurs between months.
I am using a UICollectionViewScrollLayout with a UICollectionView with 10000 indexes in 1 section. The cells are filled by calculating the day for an index. The problem I am having is when trying to resize the view to fit the correct number of weeks for the month, the collectionview doesn't appear to draw in the cells quickly enough as the scrolling and view size change happens. Having slowed the animation down, as the view size changes, it appears that cells are being removed too early from the view. This happens both with a reducing and enlarging the view. Ie, as they are about to scroll off the view they are removed before scrolling out of the view.
The layout is all done using autolayout and there is a fixed view above and then a resizable view below. As the size of the collection view changes the view below changes to fill the space. The only way I seem to have managed to achieve this behavior it is by changing the intrinsic size as per the code below. I have tried changing the frame/bounds but it doesn't seem to work with autolayout. Am I going about the resizing of the view in the right way?
Should I be moving the behaviour to the viewcontroller and change the constraints pinning the height instead.
// Scroll the view to the date given.
-(void) moveViewToDate:(NSDate*) date
{
NSIndexPath *indexPath=[self indexPathForFirstDayInMonth:date];
[self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionTop animated:YES];
[UIView animateWithDuration:0.25f animations:^{
self.isize=[self weeksInViewForDate:date];
[self invalidateIntrinsicContentSize];
[self.superview layoutIfNeeded];
}];
}
-(CGSize)intrinsicContentSize
{
return CGSizeMake(322,self.isize*46);
}
I finally worked out what was going on. Since I was committing an animation which was changing the size of the view and doing a scroll, the two seperate animations where conflicting with each other.
I eventually rewrote the collection using UIScrollView but had the same problem. I got round it by placing the UIScrollView in a UIView. The UIView was resized using a constraint on the height which was animated.
I'm trying to make my own component that behaves like a list and supports infinite scrolling (in 1-dimension : vertical or horizontal) - both directions. For eg, a vertically laid out list which the user can scroll up or down forever - without ever hitting the 'last' or 'first' item. A good use for this: a calendar that displays each month as a list item.
Anyway, there are a bunch of things to overcome. The first of which, I think, is to disable the scrollbar's bounce effects (introduced in the latest Flex 4.5 (mobile) SDK).
If I can disable the bounce effects, I'm guessing I can then add/remove items as needed to the list and it would scroll infinitely.
Any ideas?
Krishna
Personally, an infinite list would mean a lot of rework of the core List component. It's a lot of work to reverse engineer and you'll probably hit a wall. I think what you want to do is create a component from scratch and extends SkinnableContainer.
From here on out, you need to decide how to implement and what's the user interaction for an infinite list, then need to implement proper practices and reuse your item renderers.
From my experience, you can simply implement the lazy loading on the List component by adding property change event to the viewport of the list's dataGroup
list.dataGroup.addEventListener( PropertyChangeEvent.PROPERTY_CHANGE, onScrollPropertyChangeHandler );
Then in the event, listen to the vertical scroll position
if ( event.property == "verticalScrollPosition" ){
var listHeight:Number = itemList.height;
var curAnchorPoint:Number = event.newValue + listHeight;
var bottomPositionToLoad:Number = 200; // Start loading when the list nearly reach the bottom minus 200
var anchorToLoadNextPage:Number = itemList.dataGroup.contentHeight - bottomPositionToLoad;
if(curAnchorPoint >= anchorToLoadNextPage){
loadNextPage();
}
}
When loadNextPage() is running, remember to remove the property change event so the loadNextPage will not be called multiple times.
I am currently working on an Adobe AIR application that shows the user some graphical data. As this data is more in height to fit the screen height, I've placed it inside a scroller.
Now I want to take a print of this visual data, mostly some charts and lists but I only see a single page containing only the part of the screen that is currently visible to the user. I want to have the entire content inside the scroller to appear on the page.
I tried using both PrintJob and FlexPrintJob but couldn't find a way around. Can anyone please help me by providing an insight, some source code will be greatly appreciated.
Looking forward to your replies,
Thanks
This is apparently a known bug with the Flex printing library and Scroller controls. You can read about my discussions on this here:
http://forums.adobe.com/message/3626759
As a workaround, I did the following:
var printer:FlexPrintJob = new FlexPrintJob();
// Display the print dialog to the user. If they choose a printer
// and click "print", this method will return true, and we will
// spool the job to the printer they selected. If they hit cancel,
// this method will return false, and we will not attempt to send
// anything to the printer.
if(printer.start()){
// Add some padding before spooling the object to the printer.
// This will give it a reasonable margin on the printout.
itemsToPrintContainer.paddingBottom = 100;
itemsToPrintContainer.paddingTop = 100;
itemsToPrintContainer.paddingLeft = 100;
itemsToPrintContainer.paddingRight = 100;
this.removeElement(itemsToPrintContainer);
FlexGlobals.topLevelApplication.addElement(itemsToPrintContainer);
printer.addObject(itemsToPrintContainer);
printer.send();
FlexGlobals.topLevelApplication.removeElement(itemsToPrintContainer);
this.addElement(itemsToPrintContainer);
// Reset the margins to 0 for display on the screen.
itemsToPrintContainer.paddingBottom = 0;
itemsToPrintContainer.paddingTop = 0;
itemsToPrintContainer.paddingLeft = 0;
itemsToPrintContainer.paddingRight = 0;
}
That I'm doing is moving the object I want to print outside of the scroller, printing it, and then moving it back inside the scroller, so the user is unaware of any change. The user might see a brief flash on the screen while things are re-arranged, but for my case that was acceptable.
Also, the padding was an attempt to add a margin to my printed output. It will not work quite right if you have multiple pages. You may not want to add padding in your particular case.
-Josh