Java Question Create views from libraries

stefanobusetto

Active Member
Licensed User
Longtime User
is there any way to create a view from inside a library?
i mean buttons or edittext for example.
many tanks in advance
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Yes. You can create any type of object in a library.

You can inherit from ViewWrapper to make it simpler.
SeekBar for example:
B4X:
@ActivityObject
@ShortName("SeekBar")
@DontInheritEvents
@Events(values={"ValueChanged (Value As Int, UserChanged As Boolean)"})
public class SeekBarWrapper extends ViewWrapper<SeekBar>{
   @Override
   @Hide
   public void innerInitialize(final BA ba, final String eventName, boolean keepOldObject) {
      if (!keepOldObject)
         setObject(new SeekBar(ba.context));
      super.innerInitialize(ba, eventName, true);
      if (ba.subExists(eventName + "_valuechanged")) {
         getObject().setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser){
               ba.raiseEvent(getObject(), eventName + "_valuechanged", progress, fromUser);
            }

            @Override
            public void onStartTrackingTouch(SeekBar arg0) {
               
            }

            @Override
            public void onStopTrackingTouch(SeekBar arg0) {
            }
            
         });
      }
   }
   /**
    * Gets or sets the maximum allowed value.
    */
   public int getMax() {
      return getObject().getMax();
   }
   public void setMax(int value) {
      getObject().setMax(value);
   }
   /**
    * Gets or sets the current value.
    */
   public int getValue() {
      return getObject().getProgress();
   }
   public void setValue(int value) {
      getObject().setProgress(value);
   }

Note that if you inherit from ViewWrapper then you cannot have any instance fields (private or public).
 

warwound

Expert
Licensed User
Longtime User
Note that if you inherit from ViewWrapper then you cannot have any instance fields (private or public).

So what would we do if we need instance fields?

I have a class:

B4X:
public class MapViewWrapper extends ViewWrapper<MapView> {
  // no instance fields allowed
}

If i extend that class like this:

B4X:
public class OSMDroidMapView extends MapViewWrapper{
  // can i have instance fields in this class?
  private int myValue;
}

Are instance fields allowed in that second class?

Martin.
 

agraham

Expert
Licensed User
Longtime User
The instance fields limitation only applies to object wrappers that inherit AbsObjectWrapper so your second class will be affected in the same way as your first as it inherits (ultimately) from AbsObjectWrapper. Library objects that do not inherit AbsObjectWrapper are passed around as complete objects, including their instance fields.

The problem with instance fields is that on assignment of a wrapped object (or when passed as a parameter) to a variable of a different but compatible type (like ViewVar = EditTextVar) only the underlying wrapped object is transferred into a new wrapper of the specified type using the hidden getObject and setObject methods and so no original wrapper information is retained. This is why using the Tag property to maintain object data is recommended as it is a property of the underlying object and not the wrapper.

If you don't see any need for your object to be able to be passed down the View inheritance chain you can try just extending MapView itself. However you then lose all the standard properties like Width and Height and all the event handling. You may also encounter other problems, I don't know as I haven't tried it with a View derived object.
 

warwound

Expert
Licensed User
Longtime User
This is why using the Tag property to maintain object data is recommended as it is a property of the underlying object and not the wrapper.

The Tag property could be just what i need...

Could i create a simple inner Class in my MapViewWrapper to contain instance values, something like:

B4X:
class InstanceValues{
   int anInt=9;
   String myText="Hello world";
}

In the wrapper's innerInitialize method i could create an instance of that Class and assign it to the Tag property:

B4X:
((MapView)getObject()).setTag(new InstanceValues());

Then i could access those values from any wrapper method by using:

B4X:
InstanceValues myValues=(InstanceValues) ((MapView)getObject()).getTag();


I just tested it and it seems to work, the only problem would be that the Tag is accessible from B4A.
So presumably i can override ViewWrapper's getTag and setTag methods to now hide them from B4A:

B4X:
@Hide
@Override
public Object getTag() {
   return super.getTag();
}

@Hide
@Override
public void setTag(Object tag) {
   super.setTag(tag);
}

Does that all look valid?

I shall have to update my TouchImageView library as it uses a few instance fields.

Martin.
 

stefanobusetto

Active Member
Licensed User
Longtime User
onClick raises an error

hi
i had no problems creating many components inside a layout
but i am not able to have the onClick working
here is the code
if someone could help
thanks

@ActivityObject
@ShortName("SeekBar")
@DontInheritEvents
@Events(values={"Click (V As View)"})
public class xnStrUtils extends ViewWrapper<TextView>{
@Override
@Hide
public void innerInitialize(final BA ba, final String eventName, boolean keepOldObject) {
if (!keepOldObject)
{ TextView tv = new TextView(ba.context) ;
tv.setTag("tag");
tv.setText("tag");
setObject(tv);

if ( ba.subExists ( eventName + "_click" ) )
{ getObject().setOnClickListener ( new TextView.OnClickListener()
{ @Override
public void onClick ( View v )
{ setTag("tag1");
ba.raiseEvent ( getObject() , eventName + "_click" ) ;
}

} ) ;
} ;
} ;

super.innerInitialize(ba, eventName, true);

}
}
 
Top