18

I'm building a phonegap plugin which needs to render a native UI view on top of the WebView that PhoneGap provides. In iOS this is very simple, just create the view and add it to PhoneGap's webView's scrollView. This will render the control on top of the webView and allow it to scroll with the HTML content (note that this example uses a UIButton, but I will be applying this to a custom UI control):

-(void)createNativeControl:(CDVInvokedUrlCommand *)command
{
    NSDictionary* options = [command.arguments objectAtIndex:0];
    NSNumber* x = [options objectForKey:@"x"];
    NSNumber* y = [options objectForKey:@"y"];
    NSNumber* width = [options objectForKey:@"width"];
    NSNumber* height = [options objectForKey:@"height"];

    CGRect rect = CGRectMake([x floatValue], [y floatValue], [width floatValue], [height floatValue]);
    self._nativeControl = [UIButton buttonWithType:UIButtonTypeSystem];
    self._nativeControl.frame = rect;

    [self._nativeControl addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
    [self._nativeControl setTitle:@"Click me" forState:UIControlStateNormal];
    [self.webView.scrollView addSubview:self._nativeControl];

    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:result callbackId:command.callbackID];
}

I have tried doing something roughly equivalent in Android, but have not had success. Here is my most recent attempt:

@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
    System.out.println(String.format("%s action called", action));

    if ("echo".equals(action)) {
        String message = args.optString(0);
        this.echo(message, callbackContext);
        return true;
    } else if ("createNativeControl".equals(action)) {
        this.createNativeControl(callbackContext);
        return true;
    }

    return false;
}

private void createNativeControl(CallbackContext callbackContext) {
    // Find the frame layout parent and place the control on top - theoretically
    // this should appear on TOP of the webView content since the TextView child is
    // added later
    FrameLayout frameLayout = (FrameLayout) webView.getParent().getParent();

    TextView view = new TextView(frameLayout.getContext());
    view.setText("Hello, Android!");
    view.setVisibility(View.VISIBLE);

    frameLayout.addView(view, 100,100);
    callbackContext.success();
}

How can I accomplish this in Android?

Travis
  • 2,654
  • 4
  • 26
  • 46

3 Answers3

10

With Cordova Android 4.0.2, I was able to add a view on top of the webview, like this:

public class HVWMaps extends CordovaPlugin {

    @Override
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {

        FrameLayout layout = (FrameLayout) webView.getView().getParent();

        TextView textView = new TextView(layout.getContext());
        textView.setBackgroundColor(Color.BLUE);
        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(500, 500);
        params.setMargins(100, 100, 100, 100);
        textView.setLayoutParams(params);
        layout.addView(textView);
    }
}

It seems that the interface for CordovaWebView has changed recently, so this may not work with older versions. For this example, you'll also need to add <param name="onload" value="true" /> to the feature in your plugin.xml so that initialize(..) gets called:

<platform name="android">
    <config-file target="res/xml/config.xml" parent="/*">
        <feature name="YourPlugin" >
            <param name="android-package" value="com.your.plugin"/>
            <param name="onload" value="true" />
        </feature>
    </config-file>
</platform>

This doesn't scroll with the webview as you mentioned iOS does, but for my project I didn't need it to.

dwb
  • 799
  • 5
  • 14
1

So I spend some time on this myself, my solution has multiple parts:

  • You have your CordovaWebView in your layout XML
  • Your Activity extends the CordovaActivity
  • You override few methods:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.layout_page);
    super.init();
    loadUrl("file://" + getFilesDir()+"index.html");
    
    ....and other code you like...
    }
    
    
     @Override
        protected CordovaWebView makeWebView() {
            SystemWebViewEngine systemWebViewEngine =
            new SystemWebViewEngine((SystemWebView) findViewById(R.id.cordovaWebView));
    return new CordovaWebViewImpl(systemWebViewEngine);
        }
    
        @Override
        protected void createViews() {
    //must override this, otherwise crash
    if (preferences.contains("BackgroundColor")) {
        int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
        // Background of activity:
        appView.getView().setBackgroundColor(backgroundColor);
    }
            appView.getView().requestFocusFromTouch();
        }
    

So the makeWebView() is the key part, where you override the CordovaActivity's method to return your own CordovaWebView instance from the XML.

The createViews() method has to be override too, since if you check the CordovaActivity code there is a setContentView(appView.getView()), which going to cause crash otherwise. You make sure when you override you REMOVE that part.

finally the xml (not the whole content):

    <!-- The main content view -->
    <org.apache.cordova.engine.SystemWebView
    android:id="@+id/cordovaWebView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
narancs
  • 5,234
  • 4
  • 41
  • 60
  • I was tried many methods even by using java code. Finally your solution is worked to me. Thank you @Karoly !! – Jagadeesh Feb 09 '21 at 11:12
-1

Have you tried to see the order of your views? Maybe it's overlapped down your webview

//hide webview
//webview.setVisibility(View.GONE); //to test if the new view appear
webview.setZOrderOnTop(true);

//show the new view myView.setVisibility(View.VISIBLE);

myView.bringToFront();

I will asume you are 100% sure this line get a valid parent which you can add a view.

FrameLayout frameLayout = (FrameLayout) webView.getParent().getParent();

Community
  • 1
  • 1
Sulfkain
  • 5,082
  • 1
  • 20
  • 38