How to invoke onClick and onLongClick of EditText from RelativeLayout - android

I'm creating a compose screen for my app. I have a ScrollView which contains a RelativeView which in turn contains two things: the EditText where the user types a message, and an ImageView whose visibility is toggled on and off depending on whether an image is attached to the status or not. Here's that part of my layout XML.
<!-- #dimen/bigGap = 8dp -->
<ScrollView android:id="#+id/parentScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:layout_marginTop="#dimen/bigGap"
android:layout_marginRight="#dimen/bigGap"
android:layout_marginLeft="#dimen/bigGap"
android:layout_marginBottom="#dimen/bigGap"
android:layout_above="#+id/footer"
android:background="#006400"
> <!-- green background color -->
<RelativeLayout android:id="#+id/parentLinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFD700"> <!-- yellow background color -->
<EditText android:id="#+id/postText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#dddddd"
android:inputType="textMultiLine"
android:gravity="top|left"
/> <!-- gray background color -->
<ImageView android:id="#+id/postImage"
android:layout_width="#dimen/thumbnailSize"
android:layout_height="#dimen/thumbnailSize"
android:visibility="gone"
android:layout_below="#id/postText"
/>
</RelativeLayout>
</ScrollView>
Because my EditText's height is wrap_content, the whole thing starts off with a single line of gray background (the EditText) on top of a yellow background (the RelativeLayout, which fully covers the green background of the ScrollView). However, I'll later change all the views' backgrounds to white (to make them look like a single component) and it will be counter-intuitive for the user to be able to tap only that single line of EditText to make the keyboard pop up.
What I want to do is to redirect the click and long click actions of the RelativeLayout to the click and long click actions of the EditText, but my code below doesn't work. Help?
final EditText editText = (EditText) findViewById(R.id.postText);
RelativeLayout rl = (RelativeLayout) findViewById(R.id.parentLinearLayout);
rl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Logger.d("onClick invoked!");
editText.performClick();
}
});
rl.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Logger.d("onLongClick invoked!");
return editText.performLongClick();
}
});
My intention here is so that when the RelativeLayout is clicked, the keyboard pops up (as it does when done to an EditText) and when long-pressed, display the cut/copy/paste/text selection options (same behavior with EditText).

From the description, What you actually want is to open the keyboard. So your title for the question suggests a solution, not the actual problem.
call this from your click listener (or immediately when you show the page):
((InputMethodManager) myActivity
.getSystemService(Context.INPUT_METHOD_SERVICE))
.toggleSoftInput(InputMethodManager.SHOW_FORCED,
InputMethodManager.HIDE_IMPLICIT_ONLY);
Edit:
You must also call editText.requestFocus(); (#Phil is right), but from my experience it's not enough to open the keyboard, so you'll need also the ugly code above.

What you want is for your EditText to gain focus (which in-turn causes the keyboard to show):
rl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Logger.d("onClick invoked!");
editText.requestFocus();
}
});
rl.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Logger.d("onLongClick invoked!");
editText.requestFocus();
return true;
}
});

Related

Avoiding nested layouts when using a single onClickListener for an item in ListView

The premise is quite simple. I have a list of items, and each item has a TextView containing the title of the item, and a Switch showing whether the item is on or off. Instead of tapping on the Switch to toggle the item being on or off, I want to be able to click anywhere on the item to toggle it. Basically:
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:onClick="toggleSwitch">
<TextView
android:id="#+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Switch
android:id="#+id/switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>
However, this will create a nested layout when used in a screen, which might be bad for performance. I was wondering, since this ConstraintLayout is literally just a container with an onClick, whether there was a way to implement this layout in a way which avoids nested layouts. Thanks!
You can just give your textView and your button the same method that will be called on click, that way on every view click (anywhere on the item) you will call your method.
For example:
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//change you switch state
}
});
switch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//change you switch state
}
});

Touch and Multitouch events android

Consider a relative layout with three buttons of variable sizes with no anchoring arguments resulting in all being drawn at the top-left corner of the screen. Consider a single physical touch event being generated. Which of these buttons will see this event? If that all three have registered as onTouch listeners. How is the process behind this behavior ?
RelativeLayout creates a hierarchy between elements inside of it. The item you put to the lowest line will be on top of all others. And when you click, its onClick method will be called. For example you have two buttons inside of RelativeLayout like:
<Button
android:id="#+id/button_a"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You won't see this" />
<Button
android:id="#+id/button_b"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="You will see this" />
And let's say your Java code is:
findViewById(R.id.button_a).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(this, "Button A clicked.", Toast.LENGTH_LONG).show();
}
});
findViewById(R.id.button_b).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(), "Button B clicked", Toast.LENGTH_LONG).show();
}
});
In this case, you will always see the Button B clicked Toast on the screen, when you tap on these buttons.

Android onClickListener for a whole layout with a different onClickListener for an internal view

I have a simple LinearLayout that consists of a TextView and an EditText. The behaviour that I'd like to achieve is to be able to click on the EditText and handle it like normal, but treat the encompassing LinearLayout as a button that launches a new activity.
So for example, if the user clicks the space around the button in the view, a new activity is launched. If the user clicks on the EditText, then the keyboard appears and the user can populate the EditText.
Here is the simple onClickListener for the layout, which simply states that it has been clicked:
LinearLayout test = (LinearLayout)findViewById(R.id.linearLayout1);
test.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
System.out.println("layout clicked");
}
});
And the EditText has an OnFocusChangeListener that will simply state when it has gotten focus:
#Override
public void onFocusChange(View v, boolean hasFocus) {
System.out.println("EditText clicked");
}
Results:
-When the user clicks on the layout, the result "layout clicked" is correct
-When the user clicks on the edittext, the result is "layout clicked" followed by "EditText clicked", which is not correct. I'd like to ignore the linear layout's onClick event for this case.
Try creating a FrameLayout that contains a LinearLayout containing the TextView and place the EditText above the LinearLayout. This way you will not need to change anything about the listeners.
So it would be like this:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
</LinearLayout>
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="200dp" />
</FrameLayout>
Note: use margins to adjust the position of the EditText
I guess something like this should work, although it isn't the cleanest solution.
Declare a runnable that should be executed when the layout is clicked.
final Handler handler = new Handler();
Runnable layoutPressed = new Runnable() {
public void run() {
// LAYOUT CLICKED
}
};
Then start this runnable in your layout onClickListener.
LinearLayout test = (LinearLayout)findViewById(R.id.linearLayout1);
test.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
handler.postDelayed(layoutPressed, 100);
}
});
Cancel the runnable in onFocusChange.
#Override
public void onFocusChange(View v, boolean hasFocus) {
handler.removeCallbacks(layoutPressed);
// EditText clicked
}
So whenever you click the editText, the onClick of your layout will get called first, but the actions will get cancelled when onFocusChange of the editText is called.
When you click the layout, onClick will get called and will execute its actions with a 100 msec delay.
You might have to modify the delay of the runnable.

Prevent Spinner dropdown dismiss when focus changed

I have a dropdown spinner which is showed when click on a button looks like this:
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Spinner
android:id="#+id/spinMenu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:spinnerMode="dropdown"
android:visibility="invisible" />
<ListView
android:id="#+id/lvWall"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Here is snippet showing dropdown popup:
findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
spinMenu.performClick();
}
});
My spinner can show dropdown popup correctly. The problem is my layout has a listview which getting data from web service in background. When data is loading completely, all list items will be showed or refreshed, and the spinner's dropdown popup is dismiss (I even don't touch anything on screen). I think the problem is window has changed focus on other view. So how can I prevent it?
Update:
Here is my list after load data from background, it's very simple:
List<Feed> data = result;
FeedAdapter adapter = new FeedAdapter (this, data);
ListView lvWall = (ListView)findViewById(R.id.lvWall);
lvWall.setAdapter(adapter);
And data for spinner:
List<String> list = getMenus();
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, list);
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinMenu.setAdapter(dataAdapter);
If I understand correctly, you have a Spinner view which you set as invisible with the only purpose of showing the popup menu, but not the Spinner view itself. In that case, the problem is probably related to this snippet in Spinner.java, more precisely in DropdownPopup.show():
public void show(int textDirection, int textAlignment) {
...
super.show();
...
// Make sure we hide if our anchor goes away.
// TODO: This might be appropriate to push all the way down to PopupWindow,
// but it may have other side effects to investigate first. (Text editing handles, etc.)
final ViewTreeObserver vto = getViewTreeObserver();
if (vto != null) {
final OnGlobalLayoutListener layoutListener = new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (!Spinner.this.isVisibleToUser()) {
dismiss();
} else {
computeContentWidth();
...
What does this mean? Basically that the Spinner is set up with a ViewTreeObserver to be notified whenever a layout pass changes the views in the screen. And if the Spinner is not visible after that happens, the popup is dismissed. Loading the ListView evidently causes a change in the view hierarchy, and it's being fired when the data arrives from the server.
For general usage this is completely logical: if the Spinner is hidden, or it goes off screen, or something like that, it would be reasonable to make the popup go away. However, it's interferring with what you're attempting to do. It would be nice if you could somehow override isVisibleToUser(), but unfortunately it's marked as #hide, so that's not possible.
Might I suggest a workaround, like setting the Spinner visible but really small? Like, with a height of 1px? I believe that should be enough to fool this method.
Another option, and probably a more sensible one, would be to forgo the Spinner altogether and use a PopupMenu instead. You can anchor it to the Button, load it dynamically, and show it when the button is pressed. The visual effect should be the same.
If you think the problem is due to the change of focus . You can set it with multiple ways.
first create a focuschangeListener and onfocuschange do whatever you like
yourView.setOnFocusChangeListener(testListener);
#Override
public void onFocusChange(View arg0,
boolean isFocused)
{
if(isFocused)
{
//do your work here
}
else
{
}
}
And second way to prevent view from focus..
<!-- Dummy item to prevent AutoCompleteTextView from receiving focus -->
<LinearLayout
android:focusable="true" android:focusableInTouchMode="true"
android:layout_width="0px" android:layout_height="0px"/>
<!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component
to prevent the dummy from receiving focus again -->
<AutoCompleteTextView android:id="#+id/autotext"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:nextFocusUp="#id/autotext" android:nextFocusLeft="#id/autotext"/>

Error in changing button visibility onClick

I have a button which is called Check, I want it to be invisible and visible as I click each time on it, as If its visible and I clicked it will become invisible and verse vies !
But my code doesn't work ! any ideas ?
Button Check ;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings);
Check = (Button)findViewById(R.id.checkButton);
Check.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View View) {
if (View.getVisibility() == android.view.View.VISIBLE)
View.setVisibility(android.view.View.INVISIBLE);
else if (View.getVisibility() == android.view.View.INVISIBLE)
View.setVisibility(android.view.View.VISIBLE);
}
});
In my activity its visible at the beginning and when I click on it, it become invisible, BUT when I click again it stays invisible !
Change your code to this,
Check.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (v.isShown())
v.setVisibility(View.INVISIBLE);
else
v.setVisibility(View.VISIBLE);
}
But i think problem is, when button goes invisible, you are not getting any click event on it. First make sure that onClick method get call when button is invisible.
An invisible button will not dispatch any interaction event. So instead of setting button's visibility to the invisible, you can set a transparent or blank background or something like that.
But i personally believe, you should change your use-case because why one will click on the invisible button.
Try This:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="abcd" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:onClick="abc"
android:text="Button" />
</LinearLayout>
public void abc(View v) {
v.setVisibility(View.INVISIBLE);
}
public void abcd(View v) {
v.findViewById(R.id.button1).setVisibility(View.VISIBLE);
}
Invisible Items don't receive on-click event. So the only way you can receive a click on invisible is by receiving on some other view in place of the invisible view. The above solution wraps the button in a layout, so when button is invisible the on-click is passed on to layout, which handles the event and do accordingly. If you have a high usage of such layout you can also create a custom button with above mechanism.

Categories

Resources