Xamarin Zxing Barcode-Scanner Overlay - android

I am trying to create an overlay for the zxing barcode scanner with Xamarin in Visual Studio, but I dont understand how to actually implement it.
I created a small layout for it, overlay.axml, which I want to be drawn on top of the camera view.
Overlay.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:minWidth="25px"
android:minHeight="25px">
<Space
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/space1"
android:layout_weight="1" />
<ToggleButton
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/tbtnTorch"
android:layout_weight="0"
android:textOn="Torch On"
android:textOff="Torch Off" />
</LinearLayout>
Additionally, I think I need to create a class that inherits from View to bind the layout to it, but im unsure about that, this is what I got so far.
Overlay.cs:
public Overlay(Context context) : base(context)
{
}
public Overlay(Context context, IAttributeSet attrs) : base(context, attrs)
{
}
public Overlay(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
{
}
protected override void OnDraw(Android.Graphics.Canvas canvas)
{
base.OnDraw(canvas);
}
I now would like to bind the overlay to my ZXing.scanner instance, but I am not sure how to do this. This is what I got so far.
MainActivity.cs:
scanner = new MobileBarcodeScanner(this);
options = new MobileBarcodeScannerOptions();
scanner.UseCustomOverlay = true;
scanner.CustomOverlay = new Overlay(this);
[...]
var result = await scanner.scan(options);
It works just as expected when not using an overlay, but with the overlay I just get a black screen when I start to scan. EDIT: Black Screen on Emulator, no overlay at all (like expected ?) on real device.

You don't need to create another Overlay class
Just inflate the overlay like this:
var zxingOverlay = LayoutInflater.FromContext(<YOUTCONTEXT>).Inflate(Resource.Layout.overlay, null);
and this to assign it to your scanner
scanner.CustomOverlay = zxingOverlay;

Related

Reuse ViewGroup

I use this kind of ViewGroup:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/icon"
android:layout_width="16dp"
android:layout_height="16dp"
android:src="#drawable/icon1"/>
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/text1"/>
<TextView
android:id="#+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
I must use 2 such layouts In my fragment, but with different icon and title. Is there some way to implement it without copy/paste and RecyclerView?
There are several ways to deal with it.
1. Use the include tag.
1.1. Move LinearLayout to a separate file.
1.2 Add layout using the include tag two times with different ids:
<LinearLayout ...>
<include layout="#layout/your_layout" android:id="#+id/first" />
<include layout="#layout/your_layout" android:id="#+id/second" />
</LinearLayout>
1.3 Set content programmatically:
View first = findViewById(R.id.first);
first.findViewById(R.id.date).setText("05/05/2020");
View second = findViewById(R.id.second);
second.findViewById(R.id.date).setText("04/04/2020");
2. Implement a custom view.
There are two ways also. The first is to inflate layout inside FrameLayout. The second is to extend LinearLayout and add content programmatically. I'll show you the first one.
public class YourCustomView extends FrameLayout {
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
inflate(context, R.layout.your_custom_view_layout, this);
}
public MyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyView(Context context) {
this(context, null);
}
public void setContent(int iconRes, int titleRes, String data) {
findViewById(R.id.icon).setDrawableRes(iconRes);
findViewById(R.id.title).setDrawableRes(titleRes);
findViewById(R.id.data).setText(data);
}
}
3. Just copy-paste it :)
As I see icon and title are static and only data content changes, so it is not worth it to reuse such a simple layout, IMO.

Android layout ordering for overlapping VideoViews not working correctly

I'am developing an app that will show 2 videos at the same time. One small in the bottom right corner and the other full screen (kinda).
When I run the video_view on an Android 6.0.1 device the order works correctly. But when i run it on a version newer (Android 7 for example) it does not order it correctly. Also the function setZ() does nothing for me.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<nl.hacker115.drivingwithdrivepro550.CustomVideoView
android:id="#+id/roadCamera"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<nl.hacker115.drivingwithdrivepro550.CustomVideoView
android:id="#+id/faceCamera"
android:layout_width="500dp"
android:layout_height="300dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:layout_gravity="bottom|end" />
</FrameLayout>
I want the faceCamera on top of the roadCamera, how can I do this?
My CustomVideoView.java looks like this
package nl.hacker115.drivingwithdrivepro550;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.VideoView;
public class CustomVideoView extends VideoView {
private PlayPauseListener mListener;
public CustomVideoView(Context context) {
super(context);
}
public CustomVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setPlayPauseListener(PlayPauseListener listener) {
mListener = listener;
}
#Override
public void pause() {
super.pause();
if (mListener != null) {
mListener.onPause();
}
}
#Override
public void start() {
super.start();
if (mListener != null) {
mListener.onPlay();
}
}
public static interface PlayPauseListener {
void onPlay();
void onPause();
}
}
This could be what you are looking for.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<nl.hacker115.drivingwithdrivepro550.CustomVideoView
android:id="#+id/roadCamera"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<nl.hacker115.drivingwithdrivepro550.CustomVideoView
android:id="#+id/faceCamera"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:layout_gravity="bottom|end"
android:layout_marginRight="16dp" />
</FrameLayout>
My knowledge in this area is very limited, but your issue is the following: The issue is because views like VideoView and GLSurfaceView need/provide a dedicated drawing area and are handled outside of the "normal" rendering pipeline that draws UI widgets. The image that they are showing is composited into the final image at a later stage. This stage has no knowledge about in what way the view is layout-ed.
I assume this was a bug or unspecified behavior in Android 6 in what order these views get composited onto the final image.
I was able to reproduce your issue and solved it by setting
faceCameraView.setZOrderMediaOverlay(true);
on the overlay VideoView.
For more information take a look at the class description of SurfaceView which is the base class for VideoView and GLSurfaceView.

Custom view with already existing controls

I'm trying to create a re-usable control that I can just add whereever I like with already existing controls so I need no attributes, need nothing to add.
I just want the control to show up my Visual Editor when I drag the "Custom View" to the Layout.
I have a simple view_textseek.xml as example Layout that I don't want to recreate everytime I want "Text and a Seekbar" in case I use it on 3 different places (for example: a colorpicker later). Or just a control with both a "TextView" and a "SeekBar"
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:id="#+id/view_textseek_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:paddingLeft="15dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:text="#string/view_textseek_text"
android:textAppearance="?android:attr/textAppearanceMedium" />
<RelativeLayout
android:id="#+id/view_textseek_container_seekbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/view_textseek_text"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingRight="10dp"
android:paddingBottom="5dp" >
<SeekBar
android:id="#+id/view_textseek_seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:max="255"
android:progress="0" />
</RelativeLayout>
</RelativeLayout>
and this is basically my class:
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;
public class TextSeekView extends RelativeLayout
{
public TextSeekView(Context context) { super(context); init(context); }
public TextSeekView(Context context, AttributeSet attrs) { super(context, attrs); init(context); }
public TextSeekView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); }
protected void init(Context context)
{
if (!isInEditMode())
{
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_textseek, this, true);
}
}
}
As you can see, I just want to "collect" multiple already existing controls and have one "View" or "Control" to handle these. It does not show up in the editor.
Or is this due to the some old type of idiotic bug that you have to restart your environment for "custom" Views to be loaded correctly?
And I need no special attributes on my other views, nothing at all and I just want to be able to show this layout again and again when adding it, or any other layout.
Like C#, add 3 textboxes to a control just cause you use 3 textboxes each time. Then, drag that control out on the Form whenever you want 3 textboxes - nothing more to it!
Change this code:
protected void init(Context context) {
LayoutInflater layoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
layoutInflater.inflate(R.layout.view_textseek, this, true);
if (!isInEditMode()) {
// isInEditMode returns true when you show a view on graphical editor. Returns false while showing on running app.
}
}

Inflating Custom Views - Layout File Inconsistencies

No, no one answered that question, and the problem still remains... This question here is about another symptom to the same problem (please see comments below):
In Monodroid atleast, when inflating a custom view from a layout, sometimes it needs to be wrapped in a ViewGroup (ie, LinearLayout) in order to not get an exception, and other times does not.
I was wondering if anyone is familiar with this situation, and if it happens in "raw" Android as well (ie, no Monodroid) ?
I always first try without, as in
TextView1.axml
<?xml version="1.0" encoding="utf-8"?>
<Monodroid.Activity1.TextView1
android:id="#+id/text_view1"
android:layout_width="300dp"
android:layout_height="50dp"/>
but if I get an inflation exception, then I'll have to wrap it up
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Monodroid.Activity1.TextView1
android:id="#+id/text_view1"
android:layout_width="300dp"
android:layout_height="50dp"/>
</LinearLayout>
where
public class TextView1 : TextView
{
public TextView1 (Context context) : base(context) { }
public TextView1 (Context context, IAttributeSet attributes) : base(context, attributes) { }
public TextView1 (Context context, IAttributeSet attributes, int defStyle) : base(context, attributes, defStyle) { }
}
Thank you.
This layout file inflates with no containing viewgroup:
<?xml version="1.0" encoding="utf-8"?>
<fieldinspection.droid.views.custom.FieldInput
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RecordDataFieldInput"
style="#style/FieldInput"
android:layout_marginRight="0dip"/>
and this one (inner class PagedFragmentFieldInput) does not (it needs to be within a LinearLayout or else inflation exception):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll_record_data_field_input2_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<FieldInspection.Droid.Views.ComplaintView.PagedFragmentRecordDataFieldBox.PagedFragmentFieldInput
android:id="#+id/RecordDataFieldInput"
style="#style/FieldInput"
android:layout_marginRight="0dip"/>
</LinearLayout>
Its read as PagedFragment-RecordDataFieldBox, its a RecordDataFieldBox thats within a Fragment thats within a ViewPager.
I took your first sample and tried it out here. I get no error wrapping it or not.
TextViewInherit.cs:
using Android.Content;
using Android.Util;
using Android.Widget;
namespace InflationShiz
{
public class TextViewInherit : TextView
{
public TextViewInherit(Context context, IAttributeSet attrs) :
this(context, attrs, 0)
{
}
public TextViewInherit(Context context, IAttributeSet attrs, int defStyle) :
base(context, attrs, defStyle)
{
}
}
}
One.axml:
<?xml version="1.0" encoding="utf-8"?>
<inflationshiz.TextViewInherit
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
Two.axml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<inflationshiz.TextViewInherit
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Both work when I inflate in my Activity like so:
var one = LayoutInflater.Inflate(Resource.Layout.One, null);
var two = LayoutInflater.Inflate(Resource.Layout.Two, null);
I find it hard to reproduce your issue; Your code is scattered over 3 different SO questions and even more scattered because you have created answers to your own question where you try to elaborate on your initial questions.

Android: Drawing shapes programmatically on a View in layout

The documentation about this is really confusing. I simply need to add rectangels to a View I defined in my main.xml layout file. It will be a small part of the layout.
What I want to achieve is, I want to add shelves to a room but since the room shape and shelves change, I need to add them programmatically.
Below is a little part of my main.xml file, you can see the View I defined:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="#+id/relativeLayout2"
android:layout_width="600dp"
android:layout_height="650dp"
android:layout_marginTop="70dp"
android:layout_marginLeft="30dp"
android:layout_toRightOf="#+id/relativeLayout1" >
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="#string/getDirections"
android:textSize="20dp"
android:textStyle="bold" />
<View
android:id="#+id/roomplan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView3"
android:layout_marginTop="40dp"
android:background="#android:color/white" />
</RelativeLayout>
This is the custom View class I created to handle dynamic changes:
public class CustomView extends View {
ShapeDrawable roomFrame;
ArrayList<ShapeDrawable> shelfFrames;
public CustomView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
#Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
roomFrame.draw(canvas);
for (ShapeDrawable shelfFrame : shelfFrames){
shelfFrame.draw(canvas);
}
}
public void setRoom(Stage stage){
roomFrame = new ShapeDrawable(new RectShape());
roomFrame.getPaint().setColor(0xff74AC23);
roomFrame.setBounds(10, 10, stage.getWidth(), stage.getHeight());
}
public void setShelves(ArrayList<Shelf> shelves){
shelfFrames = new ArrayList<ShapeDrawable>();
for(int i = 0; i<shelves.size(); i++){
ShapeDrawable shelfFrame = new ShapeDrawable(new RectShape());
shelfFrame.getPaint().setColor(0xff74AC23);
shelfFrame.setBounds(shelves.get(i).getXPosition(), shelves.get(i).getYPosition(), shelves.get(i).getWidth(), shelves.get(i).getHeight());
shelfFrames.add(shelfFrame);
}
}
}
Now simply, when a new room plan is asked I am trying to assign this class to the View object in the xml layout:
public void loadRoomPlan(Room room, ArrayList<Shelf> shelves){
CustomView asdsView = (CustomView)findViewById(R.id.roomplan);
asdsView.setRoom(room);
asdsView.setShelves(shelves);
asdsView.invalidate();
}
I always get
Caused by: java.lang.ClassCastException: android.view.View cannot be cast to org.example.myproject.CustomView
error.
Probably I am doing this very very wrong, am I not?
The error seems to be in this line:
CustomView asdsView = (CustomView)findViewById(R.id.shopplan);
What is shopplan? In case it is a mistake and you meant R.id.roomplan try to subtitute the View in your layout for your Custom view:
<org.example.myproject.CustomView
android:id="#+id/roomplan"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView3"
android:layout_marginTop="40dp"
android:background="#android:color/white" />
UPDATE:
Try adding the other two constructors to your CustomView class:
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
When you use a custom view in an xml layout, your view has to deal with the layout attributes (the constructor AttributeSet param).

Categories

Resources