mirror of
https://github.com/status-im/react-native.git
synced 2025-01-16 12:34:17 +00:00
extract MultiSourceHelper
Reviewed By: andreicoman11 Differential Revision: D3505224 fbshipit-source-id: e731325af7fd0c1cbd600695607302c968e0f36e
This commit is contained in:
parent
3d4adb8c34
commit
2ce76771b5
@ -9,7 +9,7 @@ android_library(
|
|||||||
react_native_target('java/com/facebook/csslayout:csslayout'),
|
react_native_target('java/com/facebook/csslayout:csslayout'),
|
||||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||||
react_native_target('java/com/facebook/react/views/imagehelper:imagehelper'),
|
react_native_target('java/com/facebook/react/views/imagehelper:withmultisource'),
|
||||||
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
react_native_dep('libraries/fresco/fresco-react-native:fbcore'),
|
||||||
react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
|
react_native_dep('libraries/fresco/fresco-react-native:fresco-react-native'),
|
||||||
react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
|
react_native_dep('libraries/fresco/fresco-react-native:fresco-drawee'),
|
||||||
|
@ -43,8 +43,6 @@ import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
|
|||||||
import com.facebook.drawee.generic.RoundingParams;
|
import com.facebook.drawee.generic.RoundingParams;
|
||||||
import com.facebook.drawee.view.GenericDraweeView;
|
import com.facebook.drawee.view.GenericDraweeView;
|
||||||
import com.facebook.imagepipeline.common.ResizeOptions;
|
import com.facebook.imagepipeline.common.ResizeOptions;
|
||||||
import com.facebook.imagepipeline.core.ImagePipeline;
|
|
||||||
import com.facebook.imagepipeline.core.ImagePipelineFactory;
|
|
||||||
import com.facebook.imagepipeline.image.ImageInfo;
|
import com.facebook.imagepipeline.image.ImageInfo;
|
||||||
import com.facebook.imagepipeline.request.BasePostprocessor;
|
import com.facebook.imagepipeline.request.BasePostprocessor;
|
||||||
import com.facebook.imagepipeline.request.ImageRequest;
|
import com.facebook.imagepipeline.request.ImageRequest;
|
||||||
@ -58,7 +56,9 @@ import com.facebook.react.uimanager.PixelUtil;
|
|||||||
import com.facebook.react.uimanager.UIManagerModule;
|
import com.facebook.react.uimanager.UIManagerModule;
|
||||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||||
import com.facebook.react.views.imagehelper.ImageSource;
|
import com.facebook.react.views.imagehelper.ImageSource;
|
||||||
|
import com.facebook.react.views.imagehelper.MultiSourceHelper;
|
||||||
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
|
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper;
|
||||||
|
import com.facebook.react.views.imagehelper.MultiSourceHelper.MultiSourceResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class around Fresco's GenericDraweeView, enabling persisting props across multiple view
|
* Wrapper class around Fresco's GenericDraweeView, enabling persisting props across multiple view
|
||||||
@ -441,45 +441,16 @@ public class ReactImageView extends GenericDraweeView {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (hasMultipleSources()) {
|
if (hasMultipleSources()) {
|
||||||
setImageSourceFromMultipleSources();
|
MultiSourceResult multiSource =
|
||||||
|
MultiSourceHelper.getBestSourceForSize(getWidth(), getHeight(), mSources);
|
||||||
|
mImageSource = multiSource.getBestResult();
|
||||||
|
mCachedImageSource = multiSource.getBestResultInCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mImageSource = mSources.get(0);
|
mImageSource = mSources.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Chooses the image source with the size closest to the target image size. Must be called only
|
|
||||||
* after the layout pass when the sizes of the target image have been computed, and when there
|
|
||||||
* are at least two sources to choose from.
|
|
||||||
*/
|
|
||||||
private void setImageSourceFromMultipleSources() {
|
|
||||||
ImagePipeline imagePipeline = ImagePipelineFactory.getInstance().getImagePipeline();
|
|
||||||
final double targetImageSize = getWidth() * getHeight();
|
|
||||||
double bestPrecision = Double.MAX_VALUE;
|
|
||||||
double bestCachePrecision = Double.MAX_VALUE;
|
|
||||||
for (ImageSource source : mSources) {
|
|
||||||
final double precision = Math.abs(1.0 - (source.getSize()) / targetImageSize);
|
|
||||||
if (precision < bestPrecision) {
|
|
||||||
bestPrecision = precision;
|
|
||||||
mImageSource = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (precision < bestCachePrecision &&
|
|
||||||
(imagePipeline.isInBitmapMemoryCache(source.getUri()) ||
|
|
||||||
imagePipeline.isInDiskCacheSync(source.getUri()))) {
|
|
||||||
bestCachePrecision = precision;
|
|
||||||
mCachedImageSource = source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't use cached image source if it's the same as the image source
|
|
||||||
if (mCachedImageSource != null &&
|
|
||||||
mImageSource.getSource().equals(mCachedImageSource.getSource())) {
|
|
||||||
mCachedImageSource = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean shouldResize(ImageSource imageSource) {
|
private static boolean shouldResize(ImageSource imageSource) {
|
||||||
// Resizing is inferior to scaling. See http://frescolib.org/docs/resizing-rotating.html#_
|
// Resizing is inferior to scaling. See http://frescolib.org/docs/resizing-rotating.html#_
|
||||||
// We resize here only for images likely to be from the device's camera, where the app developer
|
// We resize here only for images likely to be from the device's camera, where the app developer
|
||||||
|
@ -2,7 +2,7 @@ include_defs('//ReactAndroid/DEFS')
|
|||||||
|
|
||||||
android_library(
|
android_library(
|
||||||
name = 'imagehelper',
|
name = 'imagehelper',
|
||||||
srcs = glob(['*.java']),
|
srcs = glob(['*.java'], excludes=['MultiSourceHelper.java']),
|
||||||
deps = [
|
deps = [
|
||||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||||
@ -12,6 +12,22 @@ android_library(
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
android_library(
|
||||||
|
name = 'withmultisource',
|
||||||
|
srcs = ['MultiSourceHelper.java'],
|
||||||
|
exported_deps = [
|
||||||
|
':imagehelper',
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
react_native_dep('libraries/fresco/fresco-react-native:imagepipeline'),
|
||||||
|
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||||
|
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
project_config(
|
project_config(
|
||||||
src_target = ':imagehelper',
|
src_target = ':imagehelper',
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.facebook.react.views.imagehelper;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.facebook.imagepipeline.core.ImagePipeline;
|
||||||
|
import com.facebook.imagepipeline.core.ImagePipelineFactory;
|
||||||
|
import com.facebook.react.views.imagehelper.ImageSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for dealing with multisource images.
|
||||||
|
*/
|
||||||
|
public class MultiSourceHelper {
|
||||||
|
|
||||||
|
public static class MultiSourceResult {
|
||||||
|
private final @Nullable ImageSource bestResult;
|
||||||
|
private final @Nullable ImageSource bestResultInCache;
|
||||||
|
|
||||||
|
private MultiSourceResult(
|
||||||
|
@Nullable ImageSource bestResult,
|
||||||
|
@Nullable ImageSource bestResultInCache) {
|
||||||
|
this.bestResult = bestResult;
|
||||||
|
this.bestResultInCache = bestResultInCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the best result overall (closest in size to the view's size). Can be null if there were
|
||||||
|
* no sources to choose from, or if there were more than 1 sources but width/height were 0.
|
||||||
|
*/
|
||||||
|
public @Nullable ImageSource getBestResult() {
|
||||||
|
return bestResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the best result (closest in size to the view's size) that is also in cache. If this would
|
||||||
|
* be the same as the source from {@link #getBestResult()}, this will return {@code null}
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
public @Nullable ImageSource getBestResultInCache() {
|
||||||
|
return bestResultInCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chooses the image source with the size closest to the target image size.
|
||||||
|
*
|
||||||
|
* @param width the width of the view that will be used to display this image
|
||||||
|
* @param height the height of the view that will be used to display this image
|
||||||
|
* @param sources the list of potential image sources to choose from
|
||||||
|
*/
|
||||||
|
public static MultiSourceResult getBestSourceForSize(
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
List<ImageSource> sources) {
|
||||||
|
// no sources
|
||||||
|
if (sources.isEmpty()) {
|
||||||
|
return new MultiSourceResult(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// single source
|
||||||
|
if (sources.size() == 1) {
|
||||||
|
return new MultiSourceResult(sources.get(0), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For multiple sources, we first need the view's size in order to determine the best source to
|
||||||
|
// load. If we haven't been measured yet, return null and wait for onSizeChanged.
|
||||||
|
if (width <= 0 || height <= 0) {
|
||||||
|
return new MultiSourceResult(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImagePipeline imagePipeline = ImagePipelineFactory.getInstance().getImagePipeline();
|
||||||
|
ImageSource best = null;
|
||||||
|
ImageSource bestCached = null;
|
||||||
|
final double viewArea = width * height;
|
||||||
|
double bestPrecision = Double.MAX_VALUE;
|
||||||
|
double bestCachePrecision = Double.MAX_VALUE;
|
||||||
|
for (ImageSource source : sources) {
|
||||||
|
double precision = Math.abs(1.0 - source.getSize() / viewArea);
|
||||||
|
if (precision < bestPrecision) {
|
||||||
|
bestPrecision = precision;
|
||||||
|
best = source;
|
||||||
|
}
|
||||||
|
if (precision < bestCachePrecision &&
|
||||||
|
(imagePipeline.isInBitmapMemoryCache(source.getUri()) ||
|
||||||
|
imagePipeline.isInDiskCacheSync(source.getUri()))) {
|
||||||
|
bestCachePrecision = precision;
|
||||||
|
bestCached = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestCached != null && best != null && bestCached.getSource().equals(best.getSource())) {
|
||||||
|
bestCached = null;
|
||||||
|
}
|
||||||
|
return new MultiSourceResult(best, bestCached);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user