I'm trying to port some Java code in to C#. where CW is a class which extends a view. OnSelectedListener is a interface with Cselected as method which takes an int argument.
setListener is a method within the class. the problem is with instantiate a interface like in Java.
private View selectedView = new View( context );
CW.setListener( new OnSelectedListener() {
#Override
public void cSelected(Integer color) {
selectedColor = color;
selectedView.setBackgroundColor( color );
}
});
Another Implementation in same method
VS.setListener( new OnSelectedListener() {
public void cSelected(Integer color) {
VS.setColor( color, true );
}
} );
Can anyone please help me port the above code to C#? Any help is appreciated. I'm using Xamarin to develop Android apps.
EDIT:
Here is the full CW class
public class HSVColorWheel : View
{
private const float SCALE = 2f;
private const float FADE_OUT_FRACTION = 0.03f;
private const int POINTER_LINE_WIDTH_DP = 2;
private const int POINTER_LENGTH_DP = 10;
private Context _context;
public HSVColorWheel(Context context, IAttributeSet attrs, int defStyle)
: base(context, attrs, defStyle)
{
this._context = context;
Init();
}
public HSVColorWheel(Context context, IAttributeSet attrs) : base(context, attrs)
{
this._context = context;
Init();
}
public HSVColorWheel(Context context) : base(context)
{
this._context = context;
Init();
}
private int scale;
private int pointerLength;
private int innerPadding;
private Paint pointerPaint = new Paint();
private void Init()
{
float density = _context.Resources.DisplayMetrics.Density;
scale = (int) (density*SCALE);
pointerLength = (int) (density*POINTER_LENGTH_DP);
pointerPaint.StrokeWidth = (int) (density*POINTER_LINE_WIDTH_DP);
innerPadding = pointerLength/2;
}
public void setListener(OnSelectedListener listener)
{
_listener = listener;
}
private float[] colorHsv = {0f, 0f, 1f};
public void setColor(Color color)
{
Color.ColorToHSV(color, colorHsv);
Invalidate();
}
}
Interface:
public interface OnSelectedListener {
void cSelected( Integer color );
}
As mentioned in the comments, since C# has language-level support for events, it provides a much cleaner approach than java's "even listener" approach.
Therefore, all listener-based java code should be converted into proper events in C#.
In this case, you're seemingly raising an event that has an int parameter. This is declared in C# like so:
//In the CW class:
public event EventHandler<int> SelectionChanged;
and then raised via an "event invocator", like so:
//In the CW class:
public void OnSelectionChanged()
{
var handler = SelectionChanged;
if (handler != null)
handler(this, //[ some int value here ]);
}
from the "consumer", or "listener" side, you simply handle the event:
//In an Activity
var CW = new CW(this);
CW.SelectionChanged += CW_SelectionChanged;
where CW_SelectionChanged can either be a an anonymous method, an actual named method, or even a lambda expression:
CW.SelectionChanged += (sender, intValue) => //[here you do something with intValue]
// -- OR --
CW.SelectionChanged += this.CW_SelectionChanged;
// then
private void CW_SelectionChanged(object sender, int intValue)
{
//[here you do something with intValue]
}
This way, you don't need to declare additional, unneeded 1-method interfaces.
Related
I am trying to show a Banner Ad from native java code to Flutter. I've tried seeing multiple plugins to write my code however when my app debugs it always shows me the error - Unhandled Exception: PlatformException(error, Cannot add a null child view to a ViewGroup, null, java.lang.IllegalArgumentException: Cannot add a null child view to a ViewGroup
Here's my Java code using PlatformViewFactory -
public class BannerFactory extends PlatformViewFactory {
private final BinaryMessenger messenger;
public BannerFactory(BinaryMessenger messenger) {
super(StandardMessageCodec.INSTANCE);
this.messenger = messenger;
}
#Override
public PlatformView create(Context context, int viewId, Object args) {
return new BannerUtil(context, this.messenger, viewId, (HashMap) args);
}
}
This is my actual BannerUtil class that contains the callbacks for my Banner Ad.
public class BannerUtil implements PlatformView {
// private FrameLayout layout;
private static final String TAG = "BannerUtil";
private int height;
private int width;
private MethodChannel channel;
private int size;
private String adUnitId;
private String placementId;
private boolean closeButton;
private int refreshTime;
private MBBannerView mtgBannerView;
public BannerUtil(Context context, BinaryMessenger messenger, int id, HashMap args) {
try {
this.size = (int) args.get("size");
this.adUnitId = (String) args.get("adUnitId");
this.placementId = (String) args.get("placementId");
this.closeButton = (boolean) args.get("closeButton");
this.refreshTime = (int) args.get("refreshTime");
this.height = (int) args.get("height");
this.width = (int) args.get("width");
this.channel = new MethodChannel(messenger, "flutter_mintegral");
// this.layout = new FrameLayout(FlutterMintegralPlugin.activity);
mtgBannerView = new MBBannerView(FlutterMintegralPlugin.activity);
mtgBannerView.init(new BannerSize(BannerSize.DEV_SET_TYPE, width, height), placementId, adUnitId);
mtgBannerView.setAllowShowCloseBtn(closeButton);
mtgBannerView.setRefreshTime(refreshTime);
mtgBannerView.setBannerAdListener(new BannerAdListener() {
#Override
public void onLoadFailed(String msg) {
Log.e(TAG, "on load failed" + msg);
}
#Override
public void onLoadSuccessed() {
Log.e(TAG, "on load successed");
}
});
if (mtgBannerView != null) {
// this.layout.removeAllViews();
mtgBannerView.load();
// FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
// FrameLayout.LayoutParams.MATCH_PARENT);
// this.layout.addView(mtgBannerView,0,layoutParams);
// layout.setVisibility(View.VISIBLE);
}
} catch (Exception e) {
Log.e("MintegralSDK", e.toString());
}
}
#Override
public View getView() {
return mtgBannerView;
}
#Override
public void dispose() {
//this.layout.removeAllViews();
if (mtgBannerView != null) {
mtgBannerView.release();
}
}
}
I need help as i'm unsure how to call FrameLayout from Java to call the banner ad in Flutter.
I am even registering my banner ad in my plugins main class like this -
private void RegistrarBanner(PlatformViewRegistry registry, BinaryMessenger messenger) {
registry.registerViewFactory("/Banner", new BannerFactory(messenger));
}
public static void registerWith(Registrar registrar) {
registrar.platformViewRegistry().registerViewFactory("/Banner", new
BannerFactory(registrar.messenger()));
}
#Override
public void onAttachedToEngine(#NonNull FlutterPluginBinding flutterPluginBinding) {
this.flutterPluginBinding = flutterPluginBinding;
this.RegistrarBanner(flutterPluginBinding.getPlatformViewRegistry(), flutterPluginBinding.getBinaryMessenger());
}
This is my Dart part of code (of my internal plugin) which calls AndroidView -
Container(
width: this.sizes[this.widget.size].width,
height: this.sizes[this.widget.size].height,
child: AndroidView(
viewType: '/Banner',
key: UniqueKey(),
creationParams: {
'closeButton': widget.closeButton,
'refreshTime': widget.refreshTime,
'adUnitId': widget.adUnitId,
'placementId': widget.placementId,
'size': this.sizes[this.widget.size].type,
'height': this.sizes[this.widget.size].height,
'width': this.sizes[this.widget.size].width
},
creationParamsCodec: StandardMessageCodec(),
),
);
I'm unsure as to where I'm going wrong? Can someone please help me.
Right now i'm using the code below in my main activity
imageAnim.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
float x = imageAnim.getX(); // width - activity's field
Log.d("works", "" + x); //return right value
}
});
But I want to move it to a class, but I keep getting errors like cannot resolve symbol getViewTreeObserver. Is there a way to fix this?
You can pass your imageAnim to you class as a parameter passable by the constructor
for example, create a class named ClassHelper as the following :
public class ClassHelper {
private ImageView imageView;
private Context context;
private float x;
ClassHelper(ImageView imageView, Context context) {
this.context = context;
this.imageView = imageView;
}
void setViewTreeObserver() {
imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
x = imageView.getX();
}
});
}
public float getX() {
return x;
}
}
and call it in like this
ClassHelper classHelper = new ClassHelper(imageAnim,getApplicationContext());
classHelper.getViewTreeObserver();
//getX() method will return the value of X
Toast.makeText(this, "" + classHelper.getX(), Toast.LENGTH_SHORT).show();
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
I have been trying for some time now to get a variable from MySurfaceView to use in my Player class. I cant seem to make it work... I tried getting the touch information from my MainActivity class but it wasn't really where I wanted it and also couldn't seem to make it work. Any help is appreciated!
MySurfaceView.java
package com.Frenchie.SurfaceView;
import ...
public class MySurfaceView extends SurfaceView implements Runnable {
Bitmap bitmap;
SurfaceHolder surfaceHolder;
int LastTouchx;
Player player;
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
#Override
public void run() {
//TODO movement here when display is working
while (true){
Update();
DrawPlayer();
}
}
public void Update(){
player.Update();
}
public void DrawPlayer(){
Canvas canvas = surfaceHolder.lockCanvas();
if (surfaceHolder.getSurface().isValid()) {
canvas.drawColor(Color.BLUE);
canvas.drawBitmap(player.getBitmap(), player.getX(), player.getY(), null);
surfaceHolder.unlockCanvasAndPost(canvas);
}
else{
Log.d("DrawPlayer", "Surface Not Valid");
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
LastTouchx = (int)event.getX();
//LastTouchy= (int)event.getY();
Log.d("Touch Value ",LastTouchx+"");
return false;
}
public int getLastTouchx() {
return LastTouchx;
}
}
Player.java
package com.Frenchie.SurfaceView;
import ...
public class Player {
//Bitmap to get character from image
private Bitmap bitmap;
//coordinates
private int x;
private int y;
//motion speed of the character
private int speed = 0;
MySurfaceView mySurfaceView;
//constructor
public Player(Context context) {
x = 75;
y = 500;
//Getting bitmap from drawable resource
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
}
//Method to update coordinate of character
public void Update(){
//updating x coordinate
if (x > mySurfaceView.getLastTouchx()){
x++;
}
else if (x < mySurfaceView.getLastTouchx()){
x--;
}
else{
Log.d("Update","Else triggered");
}
}
public Bitmap getBitmap() {
return bitmap;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Messages
E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.Frenchie.SurfaceView, PID: 26348
java.lang.NullPointerException: Attempt to invoke virtual method 'int com.Frenchie.SurfaceView.MySurfaceView.getLastTouchx()' on a null object reference
at com.Frenchie.SurfaceView.Player.Update(Player.java:36)
at com.Frenchie.SurfaceView.MySurfaceView.Update(MySurfaceView.java:68)
at com.Frenchie.SurfaceView.MySurfaceView.run(MySurfaceView.java:62)
at java.lang.Thread.run(Thread.java:762)
This was not a duplicate of the post suggested.
Override another constructor in your MySurfaceView:
public class MySurfaceView extends SurfaceView
...
public MySurfaceView(Context context) {
this(context, (AttributeSet)null)
}
public MySurfaceView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
player = new Player(context, this);
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.player);
surfaceHolder = getHolder();
//Starts the run()
Thread TestThread = new Thread(this);
TestThread.start();
}
...
In your player in constructor you can pass a surfaceView: so no need to initialize:
MySurfaceView mySurfaceView;
//constructor
public Player(Context context, MySurfaceView surfaceView) {
this.mySurfaceView = surfaceView;
x = 75;
...
Try:
MySurfaceView mySurfaceView = new MySurfaceView();
I'm trying to change attribute to custom LinearLayout class, I set the option to class with:
MyBuilder option = new MyBuilder.Builder()
.image(...)
.setCardRadius(...)
.build());
Than i call in MainActivity
MyObject obj = (MyObject) findViewById(R.id.myObject);
obj.init(context, option);
But if I call multiple times obj.init(...) with different option the builder has old value setted so the view cannot change attribute correctly.
So my question is: can I reset Builder o LinearLayout before initializate new object?
This is my LinearLayout.java:
public class MyObject extends LinearLayout{
CardView card;
ImageView image;
float cardRadiusAttr;
View rootView;
AttributeSet attributeSet;
public void init(final Context context, final MyBuilder option){
if(option != null)
{
/*
Get attribute from XML
*/
TypedArray ta = context.obtainStyledAttributes(attributeSet, R.styleable.Card, 0, 0);
try {
cardRadiusAttr = ta.getDimension(R.styleable.Card_c_cardRadius, option.getCardRadius());
} finally {
ta.recycle();
}
/*
Set up xml object.
*/
card = (CardView) findViewById(R.id.card);
image = (ImageView) findViewById(R.id.image);
card.setRadius(cardRadiusAttr);
/**
* Check if Option is set
*/
if (option.isImage() != null) {
//Set Image
}
}else{
Log.e("Initialization", "Option View not initialize!");
}
}
public MyObject(Context context, AttributeSet attrs) {
super(context, attrs);
/*
Inflater custom layout to view.
*/
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rootView = inflater.inflate(R.layout.Card, this, true);
attributeSet = attrs;
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
}
}
This is MyBuilder.java
public class MyBuilder {
private int mImage;
private float mCardRadius = 4f;
private MyBuilder(Builder builder)
{
mImage = builder.mImage;
mCardRadius = builder.mCardRadius;
}
public static class Builder{
private int mImage;
private float mCardRadius = 4f;
public Builder setCardRadius(float radius)
{
if(radius <= 0)
{
Log.e("CardRadius", "Impossible to set Card Radius lower than 0! Please Check it");
}
else {
mCardRadius = radius;
}
return this;
}
public Builder image(int image) {
if(image == 0)
{
Log.e("Image", "Impossible to set Image to 0! Please Check it");
}
else {
mImage = image;
}
return this;
}
public MyBuilder build() {
return new MyBuilder(this);
}
}
public int getImage() {
return mImage;
}
public float getCardRadius() {
return mCardRadius;
}
}
I finally found the issue.
In the init method of the MyObject you have to clean up the View after the previous use.
In this particular case, first, you pass one set of options. Based on them, View is adjusting Visibility of its controls (making button1, button2, etc. Visible). But when you pass another set of options - you have to erase all changes have been made before. (i.e. hide button1, button2, etc. and let the View to adjust Visibility of its controls once again)
Please help me with this Scala's class I want to implement it on Java here it is:
class StretchVideoView(context:Context, attr:AttributeSet)
extends VideoView(context, attrib) {
def measure(measureSpec:Int):Int = {
val specMode = View.MeasureSpec.getMode(measureSpec)
View.MeasureSpec.getSize(measureSpec)
}
override def onMeasure(widthMeasureSpec:Int, heightMeasureSpec:Int) {
val (w,h) = (measure(widthMeasureSpec), measure(heightMeasureSpec))
getHolder().setFixedSize(w,h)
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
}
I also tried to do it myself here is my Java code:
class StretchVideoView extends VideoView {
public StretchVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int measure(int measureSpec) {
int specMode = View.MeasureSpec.getMode(measureSpec)
??? View.MeasureSpec.getSize(measureSpec); // may be + here ???
return specMode; // ???
}
// and I'm not sure about this
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = measure(widthMeasureSpec);
int h = measure(heightMeasureSpec);
getHolder().setFixedSize(w,h);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Any suggestions how to implement it on Java?
Here's the original article with this code:
original code
I think you need to do something like this for measure:
public int measure(int measureSpec) {
int specMode = View.MeasureSpec.getMode(measureSpec)
return View.MeasureSpec.getSize(measureSpec);
}