Cache Images and load on scroll in UICollectionView with SDWebImageDownloader Xamarin - ios

I have a UICollectionView with Cells with images which are downloaded from url along with headers. I do it something like below :-
internal void UpdateCell(ProfileValues mdata)
{
var mUrl = "someurl";
var manager = SDWebImageManager.SharedManager;
manager.ImageCache.MaxCacheAge = 86400;
SDWebImageDownloader mDownloader = manager.ImageDownloader;
var authToken = "SomeToken"";
mDownloader.SetHttpHeaderValue(authToken, "Authorization");
mDownloader.SetHttpHeaderValue("application/json; odata=verbose", "Accept");
mDownloader.SetHttpHeaderValue("f", "X-FORMS_BASED_AUTH_ACCEPTED");
try
{
mDownloader.DownloadImage(
url: new NSUrl(mUrl),
options: SDWebImageDownloaderOptions.ProgressiveDownload,
progressBlock: (receivedSize, expectedSize) =>
{
// Track progress...
},
completedBlock: (image, data, error, finished) =>
{
if (image != null && finished)
{
InvokeOnMainThread(() =>
{
this.imgProfilePic.Image = image;
});
}
if (error != null)
{
InvokeOnMainThread(() =>
{
this.imgProfilePic.Image = errorImage;
this.imgProfilePic.BackgroundColor = UIColor.FromRGB(52, 31, 71);
//this.imgProfilePic.Layer.CornerRadius = this.imgProfilePic.Frame.Size.Width / 2;
this.imgProfilePic.ClipsToBounds = true;
this.imgProfilePic.Layer.BorderWidth = 3.0f;
this.imgProfilePic.Layer.BorderColor = UIColor.White.CGColor;
});
}
}
);
}
catch (Exception ex)
{
}
}
But on every scroll the cells are reloaded and the images are downloaded everytime. How can I cache the images and load the images from the cache on scroll? Any help is appreciated.

Use FFImageLoading package & use the class cachedImage place of Image
var cachedImage = new CachedImage() {
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 300,
HeightRequest = 300,
CacheDuration = TimeSpan.FromDays(30),
DownsampleToViewSize = true,
RetryCount = 0,
RetryDelay = 250,
TransparencyEnabled = false,
Source = "http://loremflickr.com/600/600/nature?filename=simple.jpg",
CacheKeyFactory = new CustomCacheKeyFactory(),
};

Related

I'm having problems zooming into images that are in rows of an UITableView in Xamarin.iOS

I have a tableView inside a tabView, and my rows in the tableView contain images. I would like to zoom into the said images (I put them inside a scrollView and set the max/min zoom and I set ViewForZoomingInScrollView), but it seems I can't get the zoom to trigger because they are small images 50x56 or some other gesture/event is interfeiring. I use the same zoom code on another part of my app and it works perfectly. Has anyone come across the same or similar problem or knows a possible solution?
EDIT:
protected DocumentBaseCell()
: base(UITableViewCellStyle.Default, new NSString("TableCell"))
{
...
documentImage = new UIImageView();
documentImage.Image = UIImage.FromBundle("LaunchImage");
documentImage.ContentMode = UIViewContentMode.ScaleAspectFit;
documentImage.Layer.ZPosition = 0;
imageScrollView = new UIScrollView();
imageScrollView.ClipsToBounds = false;
imageScrollView.ContentSize = new CGSize(50, 56);
imageScrollView.MaximumZoomScale = 8f;
imageScrollView.MinimumZoomScale = 1f;
imageScrollView.Add(documentImage);
imageScrollView.ViewForZoomingInScrollView += (UIScrollView sv) =>
{
imageScrollView.ContentSize = new CGSize(documentImage.Frame.Width, documentImage.Frame.Height);
return documentImage;
};
imageScrollView.DidZoom += (object sender, EventArgs e) =>
{
//(sender as UIView).Layer.ZPosition = 2000;
};
imageScrollView.ZoomingEnded += (object sender, ZoomingEndedEventArgs e) =>
{
(sender as UIScrollView).SetZoomScale(0f, true);
(sender as UIView).Layer.ZPosition = 0;
this.Layer.ZPosition = 0;
};
ContentView.Add(imageScrollView);
...
}
And this is the UpdateCell method:
internal virtual void UpdateCell(DocumentModel doc, string sup, string
docType, string user, string date, UIImage image)
{
if (image != null)
{
this.documentImage.Image = image;
}
...
}
The Frame is set aswell:
public override void LayoutSubviews()
{
base.LayoutSubviews();
imageScrollView.Frame = new CGRect(0, 2, 50, 56);
documentImage.Frame = new CGRect(0, 0, 50, 56);
}
I think you should give a frame to imageScrollView and documentImage, I download the official tableView sample project and add your code there, it zooms well.
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
imageScrollView.Frame = new CGRect(ContentView.Bounds.Width - 233, 5, 133, 133);
headingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);
subheadingLabel.Frame = new CGRect(100, 18, 100, 20);
imageView.Frame = imageScrollView.Bounds;
}
I uploaded a sample project here and you can check it.

Nativescript BitmapFactory resize does not work in iOS

I am using the BitmapFactory plugin to rezize pictures to save them as thumnails
let mutable = BitmapFactory.makeMutable(imageSource);
let rotatedBitmap = BitmapFactory.asBitmap(mutable).dispose((bmp) =>
{
return bmp.resize("80,80");
});
in Android it works perfectly, but in iOS the image returned is not resized. I read in some issues that this is because the iOS uses the default scaling..?
does anybody knnow how to resize images to square thumbnaile with a given size ?
I use undermentioned function...
imageSource = imageSourceModule.fromFile(filepath);
try
{
var mutable = BitmapFactory.makeMutable(imageSource);
var ThumbBitmap = BitmapFactory.asBitmap(mutable).dispose((bmp) =>
{
var optisizestring = "25,25";
test = bmp.resize(optisizestring);
base64JPEG = test.toBase64(BitmapFactory.OutputFormat.JPEG, 75);
img = imageSource.fromBase64(base64JPEG);
resolve( "data:image/png;base64," + base64JPEG);
global.gc(); // tried with \ without garbage collection here
});
} catch(ex) { console.log("errds " + ex); resolve (null);}
(in the BitmapFactory-plugin) BitmapFactory.ios.js i changed the resize function
iOSImage.prototype._resize = function(newSize) {
var oldImg = this._nativeObject;
try {
var ns = CGSizeMake(newSize.width, newSize.height);
UIGraphicsBeginImageContext(ns);
var context = UIGraphicsGetCurrentContext();
oldImg.drawInRect(CGRectMake(0, 0,ns.width, ns.height));
return UIGraphicsGetImageFromCurrentImageContext();
}
finally
{
UIGraphicsEndImageContext();
}
};
// // [INTERNAL] _resize() Original
// iOSImage.prototype._resize = function(newSize) {
// var oldImg = this._nativeObject;
// try {
// var ns = CGSizeMake(newSize.width, newSize.height);
// UIGraphicsBeginImageContextWithOptions(ns, false, 0.0);
// oldImg.drawInRect(CGRectMake(0, 0,
// ns.width, ns.height));
// return new iOSImage(UIGraphicsGetImageFromCurrentImageContext());
// }
// finally {
// UIGraphicsEndImageContext();
// }
// };

for embedded PDFs, can PDFJS support both scrolling and jump to a page number at the same time?

This seems like it should be very standard behavior.
I can display a scrollable PDF with:
var container = document.getElementById('viewerContainer');
var pdfViewer = new PDFJS.PDFViewer({
container: container,
});
PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) {
pdfViewer.setDocument(pdfDocument);
});
and I can display the PDF page by page with something like:
PDFJS.getDocument(URL_ANNOTATED_PDF_EXAMPLE).then(function getPdfHelloWorld(pdf) {
pdf.getPage(pageNumber).then(function getPageHelloWorld(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
});
But can't seem to find any reference in the API to both allow scrolling and jumping to a particular page, besides:
pdfViewer.currentPageNumber = 3;
which doesn't work...
So I found a way to make this work (mixed with a little Angular code, "$scope.$watch...") I now have other problems with font decoding. But here is a solution that might help someone else.
var me = this;
PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK;
var container = document.getElementById('capso-court-document__container');
function renderPDF(url, container) {
function renderPage(page) {
var SCALE = 1;
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: page.pageIndex + 1,
scale: SCALE,
defaultViewport: page.getViewport(SCALE),
textLayerFactory: new PDFJS.DefaultTextLayerFactory(),
annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory()
});
pdfPageView.setPdfPage(page);
return pdfPageView.draw();
}
function renderPages(pdfDoc) {
var pageLoadPromises = [];
for (var num = 1; num <= pdfDoc.numPages; num++) {
pageLoadPromises.push(pdfDoc.getPage(num).then(renderPage));
}
return $q.all(pageLoadPromises);
}
PDFJS.disableWorker = true;
return PDFJS.getDocument(url)
.then(renderPages);
}
$scope.$watch(function() {
return {
filingUrl: me.filingUrl,
whenPageSelected: me.whenPageSelected,
};
}, function(newVal, oldVal) {
if (newVal.filingUrl) {
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED;
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED_2;
//newVal.filingUrl = URL_EXAMPLE_PDF_MULTI_PAGE;
if (newVal.filingUrl !== oldVal.filingUrl &&
newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
//HACK - create new container for each newly displayed PDF
container.innerHTML = '';
var newContainerForNewPdfSelection = document.createElement('div');
container.appendChild(newContainerForNewPdfSelection);
renderPDF(newVal.filingUrl, newContainerForNewPdfSelection).then(function() {
if (newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
});
}
}, true);
function scrollToPage(pageNumber) {
var pageContainer = document.getElementById('pageContainer' + pageNumber);
if (pageContainer) {
container.scrollTop = pageContainer.offsetTop;
} else {
console.warn('pdf pageContainer doesn\'t exist for index', pageNumber);
}
}

Clearing Stage of as2 Photo Gallery

I'm building a website with several pages on different layers/frames in the timeline. On the "photos" layer, I wrote some code to a load a photo gallery. The problem is that the gallery doesn't disappear when I click on another page and keeps lingering over all the other content. Here is my code. Thanks in advance for any help you can give.
import mx.transitions.Tween;
import mx.transitions.easing.*;
this.createEmptyMovieClip("container",1);
var imagesNumber:Number = 9;
var scrolling:Boolean = true;
for (i=1; i<=imagesNumber; i++) {
container.attachMovie("thumb"+i,"thumb"+i+"_mc",i);
myThumb_mc = container["thumb"+i+"_mc"];
myThumb_mc._x = (i-1)*myThumb_mc._width;
myThumb_mc._y = (Stage.height-myThumb_mc._height)/2;
myThumb_mc._alpha = 50;
myThumb_mc.largerImage = i;
myThumb_mc.onRollOver = function() {
this._alpha = 100;
};
myThumb_mc.onRollOut = function() {
this._alpha = 50;
};
myThumb_mc.onRelease = function() {
this._alpha=50;
for (i=1; i<=imagesNumber; i++) {
var myClip = container["thumb"+i+"_mc"];
myClip.enabled = false;
}
scrolling = false;
_root.attachMovie("image"+this.largerImage,"large_mc",2);
large_mc._x = (Stage.width-large_mc._width)/2;
large_mc._y = (Stage.height-large_mc._height)/2;
new Tween(large_mc, "_alpha", Strong.easeOut, 0, 100, 0.5, true);
new Tween(container, "_alpha", Strong.easeOut, 100, 50, 0.5, true);
large_mc.onRelease = function() {
this.enabled=false;
scrolling = true;
var myFadeOut = new Tween(large_mc, "_alpha", Strong.easeOut, 100, 0, 0.5, true);
new Tween(container, "_alpha", Strong.easeOut, 50, 100, 0.5, true);
myFadeOut.onMotionFinished = function() {
for (i=1; i<=imagesNumber; i++) {
var myClip = container["thumb"+i+"_mc"];
myClip.enabled = true;
}
large_mc.removeMovieClip();
};
};
};
}
container.onEnterFrame = function() {
if (scrolling) {
this._x += Math.cos((-_root._xmouse/Stage.width)*Math.PI)*15;
if (this._x>0) {
this._x = 0;
}
if (-this._x>(this._width-Stage.width)) {
this._x = -(this._width-Stage.width);
}
}
};

AS2: don't perform rollout until motion finished

I have an mc with some tweens applied to it, but if you roll out before they are done they break. I don't want to disable the button while tweens are running because if you roll out while they run you confuse the user because nothing happens and you get stuck in that frame.
What I want is to acknowledge the rollout during the tween (or after) but not run until the tweens are finished. I cannot seem to access the onmotionfinished of the tween in the rollover function from the rollout function however.
Any ideas?
If it helps here is my rollover:
buttons[i].onRollOver = function() {
var oppX:Number = Stage.width-this._x;
var oppY:Number = Stage.height-this._y;
if (oppX-209.8<=20) {
var difference:Number = Math.abs(20-(oppX-209.8));
oppX += difference;
} else if (oppX+209.8>=780) {
var difference:Number = Math.abs(780-(oppX+209.8));
oppX -= difference;
}
if (oppY-172.1<=20) {
var difference:Number = Math.abs(20-(oppY-172.1));
oppY += difference;
} else if (oppY+172.1>=580) {
var difference:Number = Math.abs(580-(oppY+172.1));
oppY -= difference;
}
var TweenX:Tween = new Tween(circle, "_x", mx.transitions.easing.Strong.easeOut, circle._x, oppX, 1, true);
var TweenY:Tween = new Tween(circle, "_y", mx.transitions.easing.Strong.easeOut, circle._y, oppY, 1, true);
circle.gotoAndPlay("out");
myColor = new Color(this);
myColor.setTint(153,255,0,30);
for (MovieClip in buttons) {
delete buttons[MovieClip].onEnterFrame;
if (buttons[MovieClip] != this) {
buttons[MovieClip].enabled = false;
myColor = new Color(buttons[MovieClip]);
myColor.setTint(255,255,255,80);
myColor = new Color(buttons[MovieClip]._line);
myColor.setTint(255,255,255,80);
}
}
};
and my rollOut:
buttons[i].onRollOut = function() {
this.onMotionComplete = function() {
var TweenX:Tween = new Tween(circle, "_x", mx.transitions.easing.Strong.easeOut, circle._x, 400, 0.5, true);
var TweenY:Tween = new Tween(circle, "_y", mx.transitions.easing.Strong.easeOut, circle._y, 300, 0.5, true);
TweenY.onMotionFinished = function() {
for (MovieClip in buttons) {
buttons[MovieClip].enabled = true;
}
};
this._parent.circle.gotoAndPlay("in");
for (MovieClip in buttons) {
buttons[MovieClip].onEnterFrame = function() {
moveButtons(this);
controlButtons(this);
};
myColor = new Color(buttons[MovieClip]);
myColor.setTint(255,255,255,0);
}
};
Realised that it wasn't the tween causing most of the problems that it was the gotoandplay because i had my stop(); calls on the same frame as the markers on that movieclip causing them to get stuck.
Did have some trouble with tween (the rollout jumped back to the rollover position if its tweens were called mid tween) but I decided to push the tweens to an array making them globally accessible and purge the array onmotionfinished then in the rollout check to see if the array contains anything and if so kill off the old tweens first.
Final product:
buttons[i].onRollOver = function() {
circle.active = this;
var oppX:Number = Stage.width-this._x;
var oppY:Number = Stage.height-this._y;
if (oppX-209.8<=20) {
var difference:Number = Math.abs(20-(oppX-209.8));
oppX += difference;
} else if (oppX+209.8>=780) {
var difference:Number = Math.abs(780-(oppX+209.8));
oppX -= difference;
}
if (oppY-172.1<=20) {
var difference:Number = Math.abs(20-(oppY-172.1));
oppY += difference;
} else if (oppY+172.1>=580) {
var difference:Number = Math.abs(580-(oppY+172.1));
oppY -= difference;
}
var TweenX:Tween = new Tween(circle, "_x", mx.transitions.easing.Strong.easeOut, circle._x, oppX, 1, true);
var TweenY:Tween = new Tween(circle, "_y", mx.transitions.easing.Strong.easeOut, circle._y, oppY, 1, true);
TweenY.onMotionFinished = function () {
tweens.length = 0;
}
tweens.push(TweenX,TweenY);
circle.gotoAndPlay("out");
myColor = new Color(this);
myColor.setTint(153,255,0,30);
for (MovieClip in buttons) {
delete buttons[MovieClip].onEnterFrame;
if (buttons[MovieClip] != this) {
buttons[MovieClip].enabled = false;
myColor = new Color(buttons[MovieClip]);
myColor.setTint(255,255,255,80);
myColor = new Color(buttons[MovieClip]._line);
myColor.setTint(255,255,255,80);
}
}
};
buttons[i].onRollOut = function() {
if (tweens.length != 0) {
tweens[0].stop();
tweens[1].stop();
delete tweens[0];
delete tweens[1];
tweens.length = 0;
}
circle.gotoAndPlay("in");
var TweenX:Tween = new Tween(circle, "_x", mx.transitions.easing.Strong.easeOut, circle._x, 400, 0.5, true);
var TweenY:Tween = new Tween(circle, "_y", mx.transitions.easing.Strong.easeOut, circle._y, 300, 0.5, true);
TweenY.onMotionFinished = function() {
circle._x = 400;
circle._y = 300;
for (MovieClip in buttons) {
buttons[MovieClip].enabled = true;
}
};
for (MovieClip in buttons) {
buttons[MovieClip].onEnterFrame = function() {
moveButtons(this);
controlButtons(this);
};
myColor = new Color(buttons[MovieClip]);
myColor.setTint(255,255,255,0);
}
};

Resources