Hi have a project which I implemented ImageSlideshow and sdwebimage. Images are gotten from an API call but in the docs of ImageSlideshow SDwebImages are implemented as below
let sdWebImageSource = [SDWebImageSource(urlString: "https://images.unsplash.com/photo-1432679963831-2dab49187847?w=1080")!, SDWebImageSource(urlString: "https://images.unsplash.com/photo-1447746249824-4be4e1b76d66?w=1080")!, SDWebImageSource(urlString: "https://images.unsplash.com/photo-1463595373836-6e0b0a8ee322?w=1080")!]
which works well but for my own project I have all the images in an array and I want to display this images in the ImageSlideshow. I do not know the number of images so it is difficult to hard code it so how can I pass the array of images. ProductServices.instance.selectedProduct?.productImg[0]) this gives me the image at the first index. the images could be up to the fifth index. how can I pass this?
You can try
var allImages = [SDWebImageSource]()
if let allStr = ProductServices.instance.selectedProduct?.productImg {
for str in allStr {
allImages.append(SDWebImageSource(urlString:str))
}
}
if allImages.isEmpty {
// display custom image // or add it's default str
}
I have a code that is working with a canvas and I'd like to convert it into a layer.
The problem is that I do not want to use the build mechanism of OL3, I just want to use plain javascript.
At the moment, the problem I have is that my handleRender_ function is never called.
Here is my JS code :
ol.layer.MyLayerProperty = {
};
ol.layer.My = function (opt_options) {
var options = opt_options || {};
ol.layer.Layer.call(this, options);
this.on('render', this.handleRender_.bind(this)); //I suspect this is not working
};
ol.inherits(ol.layer.My, ol.layer.Layer);
ol.layer.My.prototype.handleRender_ = function (event) {
console.log('render process'); //never called
};
In fact, to display a canvas "above" openlayers, you simply have to use ImageCanvas.
see http://www.acuriousanimal.com/thebookofopenlayers3/chapter03_04_imagecanvas.html for example
I have an image cache class, which downloads icons if necessary and caches them. In my view controller, in viewDidAppear, I have:
// (showIcon is a UIImageView from the storyboard)
showIcon.image = [[LRImageCache imageCache] imageForURL:iconURL completionTarget:self action:#selector(updateImage:)];
If the image is already cached, it is returned here, and is correctly displayed. Otherwise, a placeholder image is returned, and the cache class attempts to download the image. When (if) successful, it calls the target/action:
- (void)updateImage:(UIImage *)image
{
showIcon.image = image;
}
Setting a breakpoint on that line confirms that 'image' is the correct, downloaded image - but it doesn't display!
I can't help but think I'm missing something really obvious...
You are calling the updateImage: which is expecting an argument, with your code you call the method but you don't provide the argument.
Consider creating an image object first like so:
UIImage *myImage = [[LRImageCache imageCache] imageForURL:iconURL completionTarget:self action:#selector(updateImage)];
Remove the argument from the updateImage method (remember to remove the colon from the selector when setting the image.
- (void)updateImage{
showIcon.image = myImage;
}
I have successfully implemented like this for lazy loading in custom list
and the code I used for this is here:Custom List With Images in Blackberry
In the linked question, I position the y coordinate of heart icon and I resolved the problemm of linked Question.
if (logoThumbnailImage != null
&& logoThumbnailImage.length > index
&& logoThumbnailImage[index] != null) {
EncodedImage img = logoThumbnailImage[index];
graphics.drawImage(0, y + 10, Display.getWidth(),
Display.getHeight() - 100, img, 0, 0, 0);
graphics.drawImage(300,
y+400,
heart.getWidth(), heart.getHeight(), heart,
0, 0, 0);
Now I want to handle click event for both; that is, for list row click and on heart click
For that I saw a post written by #Nate here Custom List Field click event. But in that code the images are not loading from server and they are static Images. I want to implement #Nate's code with my code (That is lazy loading ).
If you have any Idea please suggest how can I do that. Thanks in Advance
Assuming you start with the code I posted in this answer, and use the code you show in this question to download images from a list of URLs, then you should be able to achieve lazy image loading with the following changes:
Create a listener interface that gets notified when downloads complete:
public interface DownloadListener {
// invokes if download success
public void downloadSuccess(Bitmap bitmap);
// invokes if download failed
public void errorOccured();
}
Then, the Manager subclass that represents one list row, CustomListRow, is modified to implement this interface, and update the _thumb image when the download completes:
public class CustomListRow extends Manager implements DownloadListener, FieldChangeListener {
public void downloadSuccess(final Bitmap img) {
_data.setThumb(img);
// make sure bitmap is updated on the UI / main thread
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_thumb.setBitmap(img);
}
});
}
public void errorOccured() {
// TODO: handle error
}
Then, you'll need to add some code to create all your threads to download images in the background, and notify the DownloadListeners when the image downloads complete. You can decide where to do this. In my example, I will do this in my ListScreen class, where I instantiate the ListRander data objects and the CustomListField:
for (int i = 0; i < numberOfItem; i++) {
ListRander lr = new ListRander("Product Name " + i, icon); // icon is placeholder for thumbnail image
data.addElement(lr);
}
final CustomListField list = new CustomListField(data);
add(list);
list.setChangeListener(this);
pool = new ThreadPool(3); // 3 concurrent download threads
for (int i = 0; i < numberOfItem; i++) {
final int row = i;
// create a new runnable to download the next image, and resize it:
pool.assign(new Runnable() {
public void run() {
try {
String text=object[row].getJSONArray("UrlArray").getString(0).toString();
EncodedImage encodedImg = JPEGEncodedImage.encode(connectServerForImage(text), quality); //connectserverForImage load Images from server
EncodedImage logoThumbnail = sizeImage(encodedImg, Display.getWidth(), Display.getHeight()-100);
list.getRow(row).downloadSuccess(logoThumbnail.getBitmap());
} catch (Exception e) {
e.printStackTrace();
list.getRow(row).errorOccured();
}
}
}
});
}
You could do this in the ListScreen constructor, or whenever you have your object[] array of URLs.
You'll need to add a new method to CustomListField:
public CustomListRow getRow(int row) {
return (CustomListRow)getField(row);
}
The code above also needs a member variable added (in ListScreen) to create a thread pool:
private ThreadPool pool;
This thread pool implementation is based on this tutorial here, with very minor modifications, simply to change ArrayList (not available on BlackBerry Java) to Vector ... and removing the calls to Thread#destroy(). You'll need to copy that tutorial's ThreadPool, WorkerThread, and Done classes to your project. The above example I show creates a thread pool of 3 threads. On a single CPU smartphone, 2 or 3 threads is probably fine for your needs. Read more here if you want to get the perfect number of threads for your application.
Note: if possible, you can usually improve performance if you download images that are exactly the right size for your application, instead of burdening the network with larger images, and then resizing them inside your app. However, I realize that this depends on having some control over the images' web server, which you may not have. Just a thought for later optimization.
I am sure that I seen a good answer to this question on my travels, but can't find it now. I do recommend reviewing the BB forums here:
http://supportforums.blackberry.com/t5/Java-Development/bd-p/java_dev
as there are similar questions there.
For now, just the highlights of what you need to do:
Create an image downloading runnable to process the download - you have pretty much already done this in your previous code.
Use the Observer pattern (search the internet for this), so that the BitmapField is the Observer for the completion of your image downloading. So when the image has been downloaded, the Runnable invokes the observer, which can then update the Bitmap.
Use a Thread pool with a limited number of Threads (I would say 3), so that you do not start a whole load of image downloads at the same time. Search the internet for information on Thread Pool for help implementing this. You had not done this step in your previous example, and you can get away with running all the downloads, but I expect at some stage that this will fail.
Put these together and you have your solution. Not trivial I know. Good luck.
I'm trying to write a function on a MovieClip, and call it from the root clip. What works fine in ActionScript 3 doesn't seem to be working properly in ActionScript 2.
Frame 1 of the _root MovieClip:
var newMovieClip:MovieClip = _root.attachMovie('Notification', id, 0);
newMovieClip.SetNotificationText("Test text");
Frame 1 of the Notification MovieClip:
function SetNotificationText(inputText : String){
notificationText.text = inputText;
}
The result is that the MovieClip is created but the text is not changed.
Am I doing this wrong?
To add functions to a MovieClip in AS2, you need to use one of these methods:
Add the method to the prototype of MovieClip:
MovieClip.prototype.SetNotificationText = function(inputText:String):Void
{
if(this["notificationText"] !== undefined)
{
// If we're going to use the prototype, at least do some checks
// to make sure the caller MovieClip has the text field we expect.
this.notificationText.text = inputText;
}
}
newMovieClip.SetNotificationText("Test text");
Make the MovieClip and argument of the function:
function SetNotificationText(mc:MovieClip, inputText:String):Void
{
mc.notificationText.text = inputText;
}
SetNotificationText(newMovieClip, "Test text");
Add the method directly to the newly created MovieClip:
var newMovieClip:MovieClip = _root.attachMovie('Notification', id, 0);
newMovieClip.SetNotificationText(inputText:String):Void
{
notificationText.text = inputText;
}
newMovieClip.SetNotificationText("Test text");
Option 2 is best overall - it's the cleanest and avoids overhead of creating a new function for every new MovieClip. It also avoids messing around with the prototype, which at best should be used to add generic methods, like a removeItem() method on Array.