I am fighting with focus management of WebView: WebView messes with focus management of classic components. Here is a simple application with just an EditBox and a WebView in it which loads Google!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:and="http://schemas.android.com/apk/res/android"
xmlns:webtag="http://schemas.android.com/apk/res/com.webtag"
and:orientation="vertical" and:layout_width="fill_parent" and:layout_height="fill_parent">
<LinearLayout and:id="#+id/HorizontalScrollView02"
and:layout_width="fill_parent" and:layout_height="wrap_content">
<EditText and:id="#+id/EditText01"
and:layout_width="wrap_content" and:layout_height="wrap_content"
and:text="#+id/EditText01"/>
</LinearLayout>
<WebView and:id="#+id/uiContent"
and:layout_weight="1"
and:layout_width="fill_parent"
and:layout_height="fill_parent"/>
</LinearLayout>
And here is the Java code:
public class WebtagActivity extends Activity
{
// UI components.
private WebView mContent;
private EditText mUrl;
#Override
public void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mContent = (WebView) findViewById(R.id.uiContent);
mContent.getSettings().setJavaScriptEnabled(true);
mContent.loadUrl("http://www.google.fr/");
}
}
Based on this very simple example, it's impossible to get focus on the WebView (i.e. the google search terms input box)! However when adding "mContent.requestFocus();" during initialization, things get better. I can switch from my EditText to my WebView if I click on WebView first only... But behaviour gets soon very "erratic", with WebView sometimes not getting focus when touching it, sometimes getting it but staying with a focus rectangle around WebView fields (orange or green depending on your phone) after another touch to go back on EditText component (in which I can write text)!
Anyway, a solution I found is to add a touchListener and request focus when clicking on a WebView:
mContent.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
if (!v.hasFocus()) {
v.requestFocus();
}
break;
}
return false;
}
});
This solves almost all problems (switching from classic components to WebView and writing text) except one: WebView keeps the focusRectangle (green or orange) around fields whether it has focus or not. In the below screenshot, my EditText has the focus and receive text but WebView still looks like it has focus. I tried clearFocus but that doesn't do anything:
See the result
Any idea how to solve this?
Thanks a lot for your help!
make sure that parent layout that extends "ViewGroup" doesn't have property
android:descendantFocusability = "blocksDescendants" which prevent child layout from getting focused
This helped my problem for focus:
Webview.requestFocus(View.FOCUS_DOWN|View.FOCUS_UP);
and this for sensitive touch:
Webview.getSettings().setLightTouchEnabled(true);
Just add android:focusable="true" to your WebView layout:
<WebView android:id="#+id/uiContent"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:focusable="true"/>
Related
I have a strange situation...
I have a RecyclerView with swipeRefresh enabled... and the 1st item in my RecyclerView is a CardView having
<com.daniribalbert.customfontlib.views.CustomFontEditText
android:id="#+id/start_chat_add_comment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerVertical="true"
android:paddingTop="#dimen/general_gap_smallest"
android:paddingBottom="#dimen/general_gap_smallest"
android:gravity="top"
android:layout_toLeftOf="#id/start_chat_post_comment"
android:layout_toRightOf="#id/start_chat_attach_media"
android:background="#android:color/transparent"
android:imeOptions="actionDone"
android:textColorHint="#color/edit_text_hint_color"
android:textColor="#color/newsfeed_text_card_owner_main_text_color"
android:textSize="#dimen/font_normal"
app:font="Roboto-Regular"/>
When the recyclerview is inflated 1st time, I am able to longpress on the EditText and access the context menu. However each time I refresh the recyclerview by pulling swiperefresh (a new card is added as it was added for the 1st time), my context menu never appears on longpress on EditText.
JFYI ... i do not experience a certain vibration on the phone either on longpress on EditText at this point in time when the context menu does not show up.
I have tried looking out for some information and stuff, but nothing looks to be helpful, except at some point someone mentioned that context menu may not work if edittext is a part of popup (alertbox), and even the option of textIsSelectable = "true" did not come any handy.
Any help is much appreciated.
This fix worked for me:
edtImgDesc.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View v) {
edtImgDesc.setCursorVisible(false);
edtImgDesc.setCursorVisible(true);
}
#Override
public void onViewDetachedFromWindow(View v) {
}
})
Taken from: Long pressed broken for EditText (Or android.support.v7.widget.AppCompatEditText) after the view is recycled in RecyclerView
I am using an ImageView as a NEXT button in my Android app which is responsible for loading the next page of results into the current activity. However, despite that I bind a click listener to it, I cannot seem to capture click events on this ImageView. Here is the XML:
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="50"
android:gravity="left"
android:orientation="horizontal">
<ImageView
android:id="#+id/listBackIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/back_icon"/>
<TextView
android:id="#+id/listBackLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Prev"
android:textSize="16dip"/>
</LinearLayout>
And here is the relevant Java code:
ImageView forwardIconView = (ImageView)findViewById(R.id.listBackIcon);
// not sure if necessary; doesn't fix it anyway
forwardIconView.setClickable(true);
forwardIconView.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
++pageNumber;
try {
params.put("page", pageNumber);
} catch (JSONException e) {
// do something
}
ConnectionTask task = new ConnectionTask();
task.execute(new String[0]);
}
});
I spent about an hour researching this on Stack Overflow. I found a few places which claimed that ImageView could directly be made clickable, but most things recommended workarounds using other types of widgets.
Does anything about my layout/code stand out as being a culprit for this behavior?
Update:
I also tried binding a click listener to the TextView at the same level as the ImageView and this too failed to capture clicks. So now I am suspecting that the views are being masked by something. Perhaps something is capturing the clicks instead of the views.
I would set it up like this:
private ImageView nextButton;
nextButton = (ImageView)view.findViewById(R.id.back_button);
Util.loadImage(getActivity(),R.drawable.some_image,nextButton); //Here i would load the image, but i see you do it in XML.
nextButton.setOnClickListener(nextButtonListener);
nextButton.setEnabled(true);
View.OnClickListener nextButtonListener = new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.v(TAG, "ImageView has been clicked. do something.");
}
};
This works for me.
Why not use android:drawableLeft attribute for the textview instead of using imageView​ and textview both in a linearlayout .
<ImageView
android:id="#+id/listBackIcon"
...
android:clickable="true"
Or you can try overriding onTouchListener with ACTION_DOWN event filter, not onClickListener. Also check for parrents with android:clickable="false", they could block childs for click events.
What seemed to work for me was the accepted answer from this SO question, which suggests adding the following the every child element of the LinearLayout which I pasted in my question:
android:duplicateParentState="true"
I don't know exactly what was happening, but it appears the click events were not making it down to the TextView and ImageView. Strangely, the click events were reaching a Button, when I added one for debugging purposes. If someone has more insight into what actually happened, leave a comment and this answer can be updated.
I'm somehow getting unexpected results while trying to implement multitouch in my app. I'm never getting data for more than one pointer.
Multitouch on my phone surely works, because I can pinch-zoom in browser and detect pinch gesture with GestureDetector, but the following sample prints action=0 pointers=1 regardless of how many fingers I use to touch the screen.
Is there something in configuration/AndroidManifest or Activity creation that I need to
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.ll1).setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG","onTouch action="+event.getAction()+" pointers="+event.getPointerCount());
return false;
}
});
}
layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/ll1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
The problem was that I was returning false in onTouch, therefore new touch events have not been generated.
In my case, I realized that getPointerCount() was not changing because it was being called inside the MotionEvent.ACTION_DOWN action which meant it'd always be one.
The solution was to move it, either to MotionEvent.ACTION_MOVE if the pointer count is needed on move, either outside of the actions, to the onTouch implementation if the pointer count is needed once on touch. I hope this helps someone who may not have understood this as in my case.
I've been working on an app where a ball (bitmap) appears on the canvas at the point where the user taps on the screen. The background is an xml layout setContentView(R.layout.newsession). The canvas is a black painted canvas. When i set my java parent class setContentView(customView), the program works fine but when I add the custom surface view to my XML layout and setContentView(R.layout.newsession), the screen just shows the canvas, and the OnTouch event doesn't work. Am I doing something wrong? I've been working on this for almost a week now and I really need help. I will post my code below for the XML layout and custom surfaceView. Thanks in advance!
XML layout (newsession)
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/newSessionPage"
>
<ImageView
android:layout_width="231dp"
android:id="#+id/ivStrikeGrid"
android:layout_gravity="center"
android:layout_height="270dp"
android:layout_marginTop="18dp"
android:src="#drawable/strike_grid"
android:layout_marginBottom="10dp"
/>
<appsys.studios.CustomSurfaceViewOne
android:id="#+id/customSurfaceViewOne1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></appsys.studios.CustomSurfaceViewOne
>
</FrameLayout>
Custom SurfaceView
package appsys.studios;
public class CustomSurfaceViewOne extends SurfaceView implements Runnable{
public CustomSurfaceViewOne(Context context, AttributeSet attr) {
super(context, attr);
ourHolder = getHolder();
}
// Other stuff
}
It works fine like this:
newSeshView = new CustomSurfaceViewOne(this, null);
setContentView(newSeshView);
But nothing happens when I try to use it from the XML layout, like this:
newSeshView = new CustomSurfaceViewOne(this, null);
setContentView(R.layout.newsession);
Thanks again! :)
I think you might be missing invallidate() call of the view on its touch reading delegates.
I am not sure exactly what is happening in your code. But if i would be creating my own view and adding it in my own layout as you did.
And want it to change itself on reading touch events then i would be doing something like
in the myown view class it self
#override
// i dont remem exact signature of this method. google it or see docs
// motive is to read touch event of view and doing appropriate changes
// and redrawing the view again
public void onTouchEvent(MotionEvent me)
{
doCalculation(); // change points where to draw the ball next time. Read me
invalidate(); // tell the view re draw it self
}
Hope it helps :)
I ran into the same issue, and found your question while looking for the answer. I solved it, but I'm not sure it is the proper way.
3 files, your main activity, your surfaceview, and your XML file.
Your XML file looks ok, you have the surfaceview in it
<appsys.studios.CustomSurfaceViewOne
android:id="#+id/customSurfaceViewOne1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></appsys.studios.CustomSurfaceViewOne
>
In your activity, add implements OnTouchListener, use setContentView(R.layout.newsession); and after that, still in your onCreate() add this line CustomViewOne cvo = (CustomViewOne)findViewById(R.id.customSurfaceViewOne1) and set the listener to it by cvo.setOnTouchListener(this);
then add your onTouch
#Override
public boolean onTouch(View v, MotionEvent event) {
customSurfaceViewOne1.myOnTouch(event);
return false;
}
where myOnTouch() is a method in your customSurfaceViewOne1 class where you will do all your ontTouch events. Notice I passed in the MotionEvent event.
Again, I'm not sure if this is the proper way to do it, it's just how I got it to work. The reason I did it was just so I could have an admob ad above my surfaceview lol.
I'm trying to set up a "close to start" button in a game. The game takes the user from view to view like a maze. The user could be on any view, but I want a way to get them back to the start screen. Is there a way to find and return the ID of the current view for my findViewByID? I've found a I've tried the following code in various forms:
OnClickListener closetomain = new OnClickListener() {
#Override
public void onClick(View v) {
int currentid = v.findFocus().getId();
RelativeLayout hideme = (RelativeLayout)findViewById(currentid);
hideme.setVisibility(View.GONE);
setContentView(R.layout.main);
// RelativeLayout showme = (RelativeLayout)findViewById(R.id.startLayout);
// showme.setVisibility(View.VISIBLE);
}
};
Okay, it turns out I should have given each close button the same ID and used theisenp's suggestion for the simplest code (well, that I could understand). It also turns out that I should have started by putting each level/layout in its own activity. You live and you learn I guess. Below is my XML and java. It may not be the elegant solution but I'm not sure I care all that much as long as it works.
<ImageButton android:id="#+id/closeButton"
android:layout_height="wrap_content"
android:background="#drawable/close"
android:layout_width="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="10dp"
android:layout_marginBottom="10dp"
android:onClick="closetomain">
</ImageButton>
And here's my Java:
public void closetomain(View view) {
switch(view.getId()) {
case R.id.closeButton:
setContentView(R.layout.main);
break;
}
}
Why do you need to retrieve the id of the current view? Is it just so that you can set it's visibility to GONE? If so, there are probably better ways of implementing that same functionality.
Instead of just changing the layout with setContentView(), it would probably be a better idea to have the Start Screen be its own separate activity. When you are in any of the "maze views" you could simply use an intent to start your home screen activity like this
Intent startScreenIntent = new Intent(this, StartScreen.Class);
startActivity(startScreenIntent);
Then you won't have to worry about finding id's or changing visibilities, plus the code is cleaner, because it separates the code for your Maze levels and your Start Menu.