Barcode AR Overlays
To deliver more personalized visual feedback when scanning barcodes, override the ScanViewPlugin’s native visual feedback function.
This can be achieved using the enableBarcodeOverlays
method by passing an implementation of the BarcodeOverlayListener
object as a reference.
BarcodeOverlayListener
Interface for a callback to be invoked on BarcodeOverlayView
lifecycle events.
Methods:
Enabling Barcode Overlays
onCreate(barcodeOverlayView: BarcodeOverlayView) : List<OverlayViewHolder>
Required - called every time a BarcodeOverlayView
that is not contained on current overlays is discovered. Must return a list of OverlayViewHolder
that will be placed near the barcode.
onUpdate(viewHolders: List<OverlayViewHolder>, barcodeOverlayView: BarcodeOverlayView)
Optional - called every time a BarcodeOverlayView
needs to be repositioned.
onRemove(viewHolders: List<OverlayViewHolder>, barcodeOverlayView: BarcodeOverlayView)
Optional - called every time a BarcodeOverlayView
is no longer detected after the interval set on setClearTimeoutMills
and shall be disposed.
Setting Overlay Timeouts
getClearTimeoutMills(value: Long)
Optional - sets the max duration in milliseconds an overlay will persist on the screen after it is not detected by the scanner. Should be a value between 500 and 5000. If used, should be set before calling enableBarcodeOverlays()
method.
Default value - 1000
Avoid making long operations inside onCreate , onUpdate and onRemove . Due to the nature of their successive calls, the overlay performance can be dramatically affected by the completion period.
|
-
Kotlin
-
Java
val viewPluginBase = scanView.scanViewPlugin.activeScanViewPlugin
viewPluginBase.first().enableBarcodeOverlays(object: BarcodeOverlayListener {
override fun onCreate(barcodeOverlayView: BarcodeOverlayView): List<OverlayViewHolder> {
val buttonOverlay = Button(context).apply {
text = barcodeOverlayView.visibleBarcode.value
setOnClickListener {
Toast.makeText(context, "${barcodeOverlayView.visibleBarcode.value} barcode clicked", Toast.LENGTH_SHORT)
.show()
}
}
return listOf(OverlayViewHolder(buttonOverlay, null))
}
}
)
ScanViewPlugin scanViewPLugin = scanView.getScanViewPlugin().getFirstActiveScanViewPlugin();
scanViewPLugin.enableBarcodeOverlays(new BarcodeOverlayListener() {
@NonNull
@Override
public List<OverlayViewHolder> onCreate(@NonNull BarcodeOverlayView barcodeOverlayView) {
Button buttonOverlay = new Button(context);
buttonOverlay.setText(barcodeOverlayView.getVisibleBarcode().getValue());
buttonOverlay.setOnClickListener(view -> {
Toast.makeText(
context,
barcodeOverlayView.getVisibleBarcode().getValue()
+ " barcode clicked", Toast.LENGTH_SHORT)
.show();
});
ArrayList<OverlayViewHolder> overlayViewHolderList = new ArrayList<>();
overlayViewHolderList.add(new OverlayViewHolder(buttonOverlay, null));
return overlayViewHolderList;
}
@Override
public void onUpdate(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
BarcodeOverlayListener.super.onUpdate(viewHolders, barcodeOverlayView);
}
@Override
public void onRemove(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
BarcodeOverlayListener.super.onRemove(viewHolders, barcodeOverlayView);
}
@Override
public long getClearTimeoutMills() {
return BarcodeOverlayListener.super.getClearTimeoutMills();
}
});
Disabling BarcodeOverlays
Once the overlays are no longer required you can call disableBarcodeOverlays()
from the ScanViewPlugin
.
-
Kotlin
-
Java
val viewPluginBase = scanView.scanViewPlugin.activeScanViewPlugin
viewPluginBase.first().disableBarcodeOverlays()
ScanViewPlugin scanViewPLugin = scanView.getScanViewPlugin().getFirstActiveScanViewPlugin();
scanViewPLugin.disableBarcodeOverlays();
BarcodeOverlayView
A class that contains the VisibleBarcode
information and handles its lifecycle.
Methods:
getVisibleBarcode(): VisibleBarcode
Returns the visible barcode information.
invalidate()
Invalidates the current views associated with this barcode and triggers a new call to BarcodeOverlayListener.onCreate
passing this BarcodeOverlayView
as reference.
calling invalidate() does not trigger BarcodeOverlayListener.onRemove
|
VisibleBarcode
The class corresponding to this class on iOS is called |
A data class that contains general barcode information.
Methods:
getValue(): String
Returns the decoded barcode value.
getBarcode: Barcode
Returns whole information of barcode scan result (as described in io.anyline.plugin.result.Barcode
).
getImageRect(): CropRect
Returns the coordinates and dimensions of detected barcode image in pixels.
getBarcodeImage() : Bitmap?
Returns a cropped bitmap containing the barcode image or null
if the coordinates are invalid.
-
Kotlin
-
Java
val viewPluginBase = scanView.scanViewPlugin.activeScanViewPlugin
viewPluginBase.first().enableBarcodeOverlays(object: BarcodeOverlayListener {
val OverlayTypeSmall = 0
val OverlayTypeBig = 1
var currentOverlayType = OverlayTypeSmall
//returns a value of OverlayTypeSmall or OverlayTypeBig depending on the size of the image
private fun getOverlayTypeFromImageSize(imageRect: CropRect): Int {
val sizePixels = 400
if (imageRect.width > sizePixels || imageRect.height > sizePixels)
return OverlayTypeBig
return OverlayTypeSmall
}
override fun onCreate(barcodeOverlayView: BarcodeOverlayView): List<OverlayViewHolder> {
//stores a value of OverlayTypeSmall or OverlayTypeBig
currentOverlayType = getOverlayTypeFromImageSize(barcodeOverlayView.visibleBarcode.imageRect)
// create an instance of ImageView from small barcode detections
// or an instance of Button for bigger barcode detections
val overlayView: View = if (currentOverlayType == OverlayTypeSmall) {
ImageView(context).apply {
scaleType = ImageView.ScaleType.FIT_XY
layoutParams = ViewGroup.LayoutParams(150, 150)
setImageResource(android.R.drawable.star_off)
}
}
else {
Button(context).apply {
text = barcodeOverlayView.visibleBarcode.value
}
}
return listOf(OverlayViewHolder(overlayView, null))
}
override fun onUpdate(
viewHolders: List<OverlayViewHolder>,
barcodeOverlayView: BarcodeOverlayView
) {
if (currentOverlayType != getOverlayTypeFromImageSize(barcodeOverlayView.visibleBarcode.imageRect)) {
// calling invalidate() makes the overlay to be disposed
// and a new onCreate() will be called for a new view instance
barcodeOverlayView.invalidate()
}
}
})
ScanViewPlugin scanViewPLugin = scanView.getScanViewPlugin().getFirstActiveScanViewPlugin();
scanViewPLugin.enableBarcodeOverlays(new BarcodeOverlayListener() {
final int OverlayTypeSmall = 0;
final int OverlayTypeBig = 1;
int currentOverlayType = OverlayTypeSmall;
//returns a value of OverlayTypeSmall or OverlayTypeBig depending on the size of the image
private int getOverlayTypeFromImageSize(CropRect imageRect) {
final int sizePixels = 400;
if (imageRect.getWidth() > sizePixels || imageRect.getHeight() > sizePixels)
return OverlayTypeBig;
return OverlayTypeSmall;
}
@NonNull
@Override
public List<OverlayViewHolder> onCreate(@NonNull BarcodeOverlayView barcodeOverlayView) {
//stores a value of OverlayTypeSmall or OverlayTypeBig
currentOverlayType = getOverlayTypeFromImageSize(barcodeOverlayView.getVisibleBarcode().getImageRect());
ArrayList<OverlayViewHolder> overlayViewHolderList = new ArrayList<>();
// create an instance of ImageView from small barcode detections
// or an instance of Button for bigger barcode detections
if (currentOverlayType == OverlayTypeSmall) {
ImageView imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setLayoutParams(new ViewGroup.LayoutParams(150, 150));
imageView.setImageResource(android.R.drawable.star_off);
overlayViewHolderList.add(new OverlayViewHolder(imageView, null));
} else {
Button button = new Button(context);
button.setText(barcodeOverlayView.getVisibleBarcode().getValue());
overlayViewHolderList.add(new OverlayViewHolder(button, null));
}
return overlayViewHolderList;
}
@Override
public void onUpdate(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
if (currentOverlayType != getOverlayTypeFromImageSize(barcodeOverlayView.getVisibleBarcode().getImageRect())) {
// calling invalidate() makes the overlay to be disposed
// and a new onCreate() will be called for a new view instance
barcodeOverlayView.invalidate();
}
}
@Override
public void onRemove(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
BarcodeOverlayListener.super.onRemove(viewHolders, barcodeOverlayView);
}
@Override
public long getClearTimeoutMills() {
return BarcodeOverlayListener.super.getClearTimeoutMills();
}
});
OverlayViewHolder
Class definition for a callback to be invoked to retrieve BarcodeOverlayView
placement information.
Methods:
OverlayViewHolder(overlayView: View?, overlayConfig: OverlayConfig?)
Required - constructor that receives a View
to be placed in the FrameLayout
according with OverlayConfig
. To use default values for overlayConfig
just provide a null value.
OverlayConfig
Configuration for barcode overlays placement.
Methods:
getAnchor(): OverlayAnchorConfig
Optional - returns the desired OverlayAnchorConfig
for a BarcodeOverlayView
Value |
TOP_LEFT |
TOP_CENTER |
TOP_RIGHT |
CENTER_LEFT |
CENTER |
CENTER_RIGHT |
BOTTOM_LEFT |
BOTTOM_CENTER |
BOTTOM_RIGHT |
Default value - CENTER (anchored to the center of the barcode)
getSizeDimension(): OverlayDimensionConfig
Optional - returns the desired size using OverlayDimensionConfig
for a BarcodeOverlayView
Default value - detected barcode width and height
-
Kotlin
-
Java
OverlayDimensionConfig().apply {
scaleX = OverlayScaleConfig().apply {
scaleValue = 1.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY
}
scaleY = OverlayScaleConfig().apply {
scaleValue = 1.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY
}
}
OverlayScaleConfig xScaleOverlayScaleConfig = new OverlayScaleConfig();
xScaleOverlayScaleConfig.setScaleValue(1.0);
xScaleOverlayScaleConfig.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY);
OverlayScaleConfig yScaleOverlayScaleConfig = new OverlayScaleConfig();
yScaleOverlayScaleConfig.setScaleValue(1.0);
yScaleOverlayScaleConfig.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY);
OverlayDimensionConfig sizeOverlayDimensionConfig = new OverlayDimensionConfig();
sizeOverlayDimensionConfig.setScaleX(xScaleOverlayScaleConfig);
sizeOverlayDimensionConfig.setScaleY(yScaleOverlayScaleConfig);
getOffsetDimension(): OverlayDimensionConfig
Optional - returns the desired offset using OverlayDimensionConfig
for a BarcodeOverlayView
Default value - no offset
-
Kotlin
-
Java
OverlayDimensionConfig().apply {
scaleX = OverlayScaleConfig().apply {
scaleValue = 0.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.NONE
}
scaleY = OverlayScaleConfig().apply {
scaleValue = 0.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.NONE
}
}
OverlayScaleConfig xScaleOverlayScaleConfig = new OverlayScaleConfig();
xScaleOverlayScaleConfig.setScaleValue(0.0);
xScaleOverlayScaleConfig.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.NONE);
OverlayScaleConfig yScaleOverlayScaleConfig = new OverlayScaleConfig();
yScaleOverlayScaleConfig.setScaleValue(0.0);
yScaleOverlayScaleConfig.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.NONE);
OverlayDimensionConfig offsetOverlayDimensionConfig = new OverlayDimensionConfig();
offsetOverlayDimensionConfig.setScaleX(xScaleOverlayScaleConfig);
offsetOverlayDimensionConfig.setScaleY(yScaleOverlayScaleConfig);
OverlayDimensionConfig
Class containing OverlayScaleConfig
for X and Y
scaleX: OverlayScaleConfig
scaleY: OverlayScaleConfig
Parameters - OverlayScaleConfig
for X and Y axes.
OverlayScaleConfig
Class containing scale information for a single axe.
scaleValue: Float
scaleType: OverlayScaleTypeConfig
Parameters - a Float
value to be used with the OverlayScaleTypeConfig
for positioning overlays.
OverlayScaleTypeConfig
Enum class containing possible values for scaling overlays.
Value |
Description |
NONE |
No scaling |
OVERLAY |
Scale based on barcode size |
FIXED_PX |
Fixed size in pixels |
KEEP_RATIO |
Keep original view size ratio |
-
Kotlin
-
Java
val viewPluginBase = scanView.scanViewPlugin.activeScanViewPlugin
viewPluginBase.first().enableBarcodeOverlays(object: BarcodeOverlayListener {
override fun onCreate(barcodeOverlayView: BarcodeOverlayView): List<OverlayViewHolder> {
var imageRes = android.R.drawable.star_off
var backColor = android.R.color.background_light
if (barcodeOverlayView.visibleBarcode.barcode.format.equals(BarcodeFormat.CODE_128.name)) {
//setting a specific color and image for CODE 128 barcodes
imageRes = android.R.drawable.star_on
backColor = android.R.color.background_dark
}
val frameOverlayViewHolder = OverlayViewHolder(
View(context).apply {
setBackgroundResource(backColor)
}, null //OverlayConfig is omitted to use default barcode surrounding placement
)
val imageOverlayViewHolder = OverlayViewHolder(
ImageView(context).apply {
scaleType = ImageView.ScaleType.FIT_XY
layoutParams = ViewGroup.LayoutParams(150, 150)
setImageResource(imageRes)
}, OverlayConfig().apply {
anchor = OverlayConfig.OverlayAnchorConfig.TOP_CENTER
sizeDimension = OverlayDimensionConfig().apply {
scaleX = OverlayScaleConfig().apply {
scaleValue = 1.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.KEEP_RATIO
}
scaleY = OverlayScaleConfig().apply {
scaleValue = 1.0
scaleType = OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY
}
}
}
)
return listOf(frameOverlayViewHolder, imageOverlayViewHolder)
}
})
ScanViewPlugin scanViewPLugin = scanView.getScanViewPlugin().getFirstActiveScanViewPlugin();
scanViewPLugin.enableBarcodeOverlays(new BarcodeOverlayListener() {
@NonNull
@Override
public List<OverlayViewHolder> onCreate(@NonNull BarcodeOverlayView barcodeOverlayView) {
int imageRes = android.R.drawable.star_off;
int backColor = android.R.color.background_light;
if (barcodeOverlayView.getVisibleBarcode().getBarcode().getFormat().equals(BarcodeFormat.CODE_128.name())) {
//setting a specific color and image for CODE 128 barcodes
imageRes = android.R.drawable.star_on;
backColor = android.R.color.background_dark;
}
View view = new View(context);
view.setBackgroundResource(backColor);
OverlayViewHolder frameOverlayViewHolder = new OverlayViewHolder(
view,
null //OverlayConfig is omitted to use default barcode surrounding placement
);
ImageView imageView = new ImageView(context);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setLayoutParams(new ViewGroup.LayoutParams(150, 150));
imageView.setImageResource(imageRes);
OverlayScaleConfig imageScaleX = new OverlayScaleConfig();
imageScaleX.setScaleValue(1.0);
imageScaleX.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.KEEP_RATIO);
OverlayScaleConfig imageScaleY = new OverlayScaleConfig();
imageScaleY.setScaleValue(1.0);
imageScaleY.setScaleType(OverlayScaleConfig.OverlayScaleTypeConfig.OVERLAY);
OverlayDimensionConfig imageSizeDimension = new OverlayDimensionConfig();
imageSizeDimension.setScaleX(imageScaleX);
imageSizeDimension.setScaleY(imageScaleY);
OverlayConfig imageOverlayConfig = new OverlayConfig();
imageOverlayConfig.setAnchor(OverlayConfig.OverlayAnchorConfig.TOP_CENTER);
imageOverlayConfig.setSizeDimension(imageSizeDimension);
OverlayViewHolder imageOverlayViewHolder = new OverlayViewHolder(
imageView,
imageOverlayConfig
);
ArrayList<OverlayViewHolder> overlayViewHolderList = new ArrayList<>();
overlayViewHolderList.add(frameOverlayViewHolder);
overlayViewHolderList.add(imageOverlayViewHolder);
return overlayViewHolderList;
}
@Override
public void onUpdate(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
BarcodeOverlayListener.super.onUpdate(viewHolders, barcodeOverlayView);
}
@Override
public void onRemove(@NonNull List<? extends OverlayViewHolder> viewHolders, @NonNull BarcodeOverlayView barcodeOverlayView) {
BarcodeOverlayListener.super.onRemove(viewHolders, barcodeOverlayView);
}
@Override
public long getClearTimeoutMills() {
return BarcodeOverlayListener.super.getClearTimeoutMills();
}
});