I'm trying to refresh Canvas on DoubleTap in android. I use GestureDetector in custom View.
final GestureDetector mDetector = new GestureDetector(
getContext(), new GestureDetector.OnGestureListener() {
#Override
public boolean onDoubleTap(MotionEvent e) {
invalidate();
return true;
}
}
But I'm getting the error
The method onDoubleTap(MotionEvent) of type new
GestureDetector.OnGestureListener(){} must override or implement a
supertype method
with
Remove '#Override' annotation
solution. I remove override and get this warning
The method onDoubleTap(MotionEvent) from the type new
GestureDetector.OnGestureListener() {} is never used locally.
Then I tried to test whether this works and made a function to change TextView string whenever I DoubleTap. Nothing happens.
I also looked at GestureDetector Reference for explanations, but they don't even have DoubleTap there, which everybody uses. What should I do?
try this
final GestureDetector mDetector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
});
For the ones, who were wondering how to set it also to the corresponding view:
final GestureDetector gDetector = new GestureDetector(getBaseContext(), new GestureDetector.SimpleOnGestureListener() {
#Override
public boolean onDown(MotionEvent e) {
return true;
}
#Override
public boolean onDoubleTap(MotionEvent e) {
doIt();
return true;
}
});
// Set it to the view
mButton.setOnTouchListener((v, event) -> gDetector.onTouchEvent(event));
My approach to this problem was different since I needed to perform something for the onClick listener as well, and also it was in a list view, so I needed to know what was the item content.
here is my approach using kotlin Job:
At the top of the class I've declared something like this:
private var doubleTapTimerJob: Job = Job()
private var clickedViewItem: CartViewItem? = null
val DOUBLE_TAP_DELAY = 200L
where CartViewItem is the model that is used in the list.
and this is my onClickListener logic:
if (clickedViewItem == null || clickedViewItem != cartViewItem) {
doubleTapTimerJob.cancel()
doubleTapTimerJob = lifecycleScope.launch {
delay(DOUBLE_TAP_DELAY)
clickedViewItem = null
}
clickedViewItem = cartViewItem
onClicked(cartViewItem)
} else {
onDoubleClicked(cartViewItem)
clickedViewItem = null
doubleTapTimerJob.cancel()
}
here I wait for 200 milliseconds for the second tap, and if it didn't happen, I will make clickedViewItem null, so its not valid anymore
Related
Image1
Image2
I wanna make "btn_34" in [image2] to move "game39" class if user clicked "btn_21_2" in [image1]. If user didn't click "btn_21_2", Wanna make "btn_34" to move "game30". Which thing should I add or change in these pic?
Please post code and not images of code.
3 options: Quick, Standard, Best.
1-> Place public static boolean button21Flag = false; in your game17.class and when they click button btn_21_2 change it to true. When you get to btn_34.
if(game17.button21Flag)
intent = new Intent(game26.class,game39.class)
else
intent = new Intent(game26.class,game30.class)
2 -> Place an Extra into the Intent when btn_21_2 is clicked. And keep passing it, until you need it in btn_34.
btn_21_2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
Intent intent = new Intent(game17.class,game18.class);
intent.putExtra("button21Flag", true);
startActivity(intent);
}
});
// in btn_34 getIntent.getBooleanExtra("button21Flag", false);
3-> This solution is based on how complex and convoluted your code will get, if you keep approaching it this way.
Create a singleton called GameState and have it keep track of the game state. Anything you would like to keep track of should go in here and when you get to the point where you need it you can access it anywhere via a static context.
(EDIT) To respond to your answer.
public static boolean game17Flag = false;
btn_21_2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
game17Flag = true;
Intent intent = new Intent(game17.this, game18.class);
startActivity(intent);
}
});
//Remove this completely
{
if (btn_21_2.isPressed()) {
game17Flag = true;
}
}
I am developing an application for Xamarin.UWP which is trying to inject Javascript into a local html file (uri: ms-appdata:///local/index.html) like so:
async void OnWebViewNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
{
if (args.IsSuccess)
{
// Inject JS script
if (Control != null && Element != null)
{
foreach (var f in Element.RegisteredFunctions.Where(ff => !ff.IsInjected))
{
await Control.InvokeScriptAsync("eval", new[] { string.Format(JavaScriptFunctionTemplate, f.Name) });
f.Injected();
}
}
}
}
Then when the Javascript method is called this will call the OnWebViewScriptNotify method so that I can proccess the request in my application.
The trouble is this doesnt work for some kind of security reasons:
This was a policy decision we made that we have had feedback on so we
re-evaluate it. The same restriction doesn't apply if you use
NavigateToStreamUri together with a resolver object. Internally that's
what happens with ms-appdata:/// anyway.
I then tried what is advised in this case which was to use a resolver as mentioned here: https://stackoverflow.com/a/18979635/2987066
But this has a massive affect on performance, because it is constantly converting all files to a stream to load in, as well as certain pages loading incorrectly.
I then looked at using the AddWebAllowedObject method like so:
private void Control_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
if (Control != null && Element != null)
{
foreach (var f in Element.RegisteredFunctions)
{
var communicator = new HtmlCommunicator(f);
Control.AddWebAllowedObject("HtmlCommunicator", communicator);
}
}
}
Where HtmlCommunicator is:
[AllowForWeb]
public sealed class HtmlCommunicator
{
public JSFunctionInjection Function { get; set; }
public HtmlCommunicator(JSFunctionInjection function)
{
Function = function;
}
public void Fred()
{
var d = 2;
//Do something with Function
}
}
and in my html it is like so:
try { window.HtmlCommunicator.Fred(); } catch (err) { }
But this doesn't work either.
So is there a way to work around this rediculous limitation?
So I found this answer: C# class attributes not accessible in Javascript
It says:
I believe you need to define the method name starting with a lower
case character.
For example: change GetIPAddress to getIPAddress.
I tested it on my side and found if I use the upper case name
'GetIPAddress', it won't work. But if I use getIPAddress, it works.
So I tried this:
I created a new project of type Windows Runtime Component as suggested here and I changed my method names to lower case so I had:
[AllowForWeb]
public sealed class HtmlCommunicator
{
public HtmlCommunicator()
{
}
public void fred()
{
var d = 2;
//Do something with Function
}
}
In my javascript I then had:
try { window.HtmlCommunicator.fred(); } catch (err) { }
and in my main UWP project I referenced the new Windows Runtime Component library and had the following:
public HtmlCommunicator communicator { get; set; }
private void Control_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
if (Control != null && Element != null)
{
communicator = new HtmlCommunicator();
Control.AddWebAllowedObject("HtmlCommunicator", communicator);
}
}
And this worked!
I have some javascript running in WebView. In this Javascript code there a function which returns a boolean. I want to check the return value from this function and depends on it hide or not a view in my android code. I tried for one day and it does not work. Do someone knows where is my error? This is my code:
public class MyActivity extends Activity {
private static final String JS_INTERFACE = "Android";
....
webView.getSettings().setJavaScriptEnabled(true);
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
webView.loadUrl(getUrl(this.getResources().getString(R.string.host)));
webView.addJavascriptInterface(new WebViewJavaScriptInterface(this), JS_INTERFACE);
webView.setWebViewClient(new WebViewClient(progressBar, this, tvError));
webView.setWebChromeClient(new WebChromeClient(progressBar));
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
}
public class WebViewJavaScriptInterface
{
....
#JavascriptInterface
public void showAdBanner(String jsResult) {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
You're setting the visibility to View.GONE in both cases of the if (jsResult == "true") if statement.
I think the window in the js is unneeded, so
webView.loadUrl("javascript:window.Android.showAdBanner(showSdkAd())");
Should be
webView.loadUrl("javascript:Android.showAdBanner(showSdkAd())");
Also, the javascript callback will be executed in a background thread, so you need to move to the main thread (posting a runnable to a view, runOnUiThread, using a handler etc), before performing Ui operations.
If you have a reference to a View, you can do:
#JavascriptInterface
public void showAdBanner(String jsResult) {
viewReference.post(new Runnable() {
public void run() {
if (jsResult == "true") {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
} else {
((Activity) context).findViewById(R.id.adView).setVisibility(View.GONE);
}
}
}
Since, you have a reference to the activity, you can replace viewReference.post with ((Activity) context).runOnUiThread
If you initialise a Handler on the main thread, it will be bound to the main thread. As a field of the Activity, you could have:
private Handler mHandler = new Handler();
And then replace viewReference.post with mHandler.post
You could also make a custom Handler that implements handleMessage(Message msg) and then you can just send it an empty message. However, you should read https://techblog.badoo.com/blog/2014/08/28/android-handler-memory-leaks/ to avoid memory issues.
I'm developing an hybrid app in Android. I want to show an alertDialog(instead of an alert/confirm JavaScript function) and when the user touch YES, return a true response to JavaScript, otherwise return false. Then if it's true I want to redirect to another URL.
Here's the 'binding JavaScript code to Android code':
public class WebAppInterface {
Context mContext;
boolean result;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
}
And the JavaScript part:
if (Android.showAlert('Title example', 'Are you sure you wanna exit?') == true) {
window.location = "http://newurl.com/example.html";
}
It actually works but not as it supposed to do. JavaScript receives the result when I open again the alertDialog and then redirect to the new URL, It needs to redirect at the moment the user touch the YES button.
I've done lot of research on this particular case and sadly found nothing.
Thank you.
Here is the Javascript Code. Add a function to navigate to a page. Like doNavigate:
<script type="text/javascript">
function showAlert(toast) {
navigate = Android.showAlert('Title example', 'Are you sure you wanna exit?');
}
function doNavigate(){
window.location = "http://www.google.com"
}
</script>
And here is the Android code for show alert. Call the javascript method from onClick positive button:
#JavascriptInterface
public boolean showAlert(String title, String message) {
new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
((Activity)mContext).runOnUiThread(new Runnable() {
#Override
public void run() {
myWeb.loadUrl("javascript:doNavigate()");
}
});
result = true;
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
result = false;
}
})
.show();
return result;
}
Keep a reference of the WebView in your WebAppInterface:
public static class WebAppInterface{
Context mContext;
boolean result;
WebView myWeb;
/** Instantiate the interface and set the context */
WebAppInterface(Context c, WebView webView) {
mContext = c;
myWeb = webView;
}
Probably when on click gets executed it doesnt immediately return the desired boolean value.
I'm thinking the next time you open the dialog then the if statment gets executed.
Maybe you can try injecting the logic through the constructor using an interface or class. And when the positive button is clicked it will call a method of that interface setting window.location
Hope it helps . Good luck
I am trying to interact with the JavaScript through Android. i followed the tutorial found [here][1].
But I am getting the following warning.system.out.println is also not working
WARN/KeyCharacterMap(310): No keyboard for id 0
WARN/KeyCharacterMap(310): Using default keymap: /system/usr/keychars/qwerty.kcm.bin
WARN/InputManagerService(66): Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#44faba68
cause of which I am not able to pass values or get the values back
webEngine=(WebView) findViewById(R.id.webengine);
webEngine.getSettings().setJavaScriptEnabled(true);
webEngine.addJavascriptInterface(this, "android");
webEngine.setWebViewClient(new WebViewClient()
{
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url)
{
return false;
}
});
webEngine.loadUrl("http://www.a11y.in/a11y_fs/");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
// TODO Auto-generated method stub
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
// Handle item selection
switch (item.getItemId())
{
case R.id.edit:
webEngine.loadUrl("javascript:var path =android.path();var newContent=android.newContent();var name = 'myname'; android.toast(name););
return true;
case R.id.renarration:
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public String path()
{
return xPath = "//H3[#id='header']";
}
public String newContent()
{
return newContent ="my New Home";
}
public void toast(String x)
{
Toast.makeText(this, "hello from js"+x, Toast.LENGTH_LONG).show();
}
plz help
First, those error messages are not related to your code, so you can just ignore them.
Then there seems to be some error with the quotes, there do not match (which also breaks the syntax highlighting in your question)... or it might be only this site which parses it incorrectly...
I also don't see the "path" method in your class, although you are accessing it from javascript. Similarly the "newContent" method.