OnClick event on TextView stops RippleEffect on CardView - android

I have a TextView inside a CardView. When enabling the ripple effect for Lollipop on the CardView by adding a OnClick event and adding the property:
android:foreground="?android:attr/selectableItemBackground"
It works fine. But after adding a OnClick event to the TextView, the ripple effect still shows up when I click outside of the TextView, but it won't show when clicking on the TextView area.
Is there away to show the ripple even when I click the TextView?
Here is xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<android.support.v7.widget.CardView
android:id="#+id/news_card"
android:foreground="?android:attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/text"
android:text="Test String"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v7.widget.CardView>
</RelativeLayout>
Here is the code:
protected void onCreate (Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
View v = findViewById (R.id.news_card);
v.setOnClickListener (new View.OnClickListener () {
#Override public void onClick (final View v) {
}
});
View textView = findViewById (R.id.text);
textView.setOnClickListener (new View.OnClickListener () {
#Override public void onClick (final View v) {
}
});
}

One option is to forward the pressed state and hotspot position through to the parent view.
// Since the host view actually supports clicks, you can return false
// from your touch listener and continue to receive events.
myTextView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent e) {
// Convert to card view coordinates. Assumes the host view is
// a direct child and the card view is not scrollable.
float x = e.getX() + v.getLeft();
float y = e.getY() + v.getTop();
// Simulate motion on the card view.
myCardView.drawableHotspotChanged(x, y);
// Simulate pressed state on the card view.
switch (e.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
myCardView.setPressed(true);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
myCardView.setPressed(false);
break;
}
// Pass all events through to the host view.
return false;
}
});

Related

Android : flowlayout inner button with close icon onclick event

I have a requirement to create a button with close icon like as below:
i have use button and i have fatch problem when i click on button remove button.
but my requirement is onclick close icon when remove form list.
so please help me which control use so my problem solution.
Use this code it will solved your problem
buttondelete.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int DRAWABLE_RIGHT = 2;
if(event.getAction() == MotionEvent.ACTION_UP) {
if(event.getRawX() >= (buttondelete.getRight() - buttondelete.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
// your action here
return true;
}
}
return false;
}
});
i would add to flow layout customLaout which contains of grey background and linear layout with 2 elements inside. TextView and ImageView.
Both has own ClickListeners
something like:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_gravity="center"
android:text="Example Text"
android:id="#+id/buttonTextView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="#+id/buttonExitIcon"
android:src="#drawable/your_image_source"
/>
</LinearLayout>
and add Click listeners for both imageView and TextView
{
RelativeLayout mainView = (RelativeLayout)findViewById(R.id.item);
View child = getLayoutInflater().inflate(R.layout.child, null);
Button bt_close = (Button)child.findviewById(R.id.btnclose);
bt_put.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
RelativeLayout pView = (RelativeLayout)v.getParent();
mainView.removeView(pView);
}
});
mainView.addView(child);
}
Create a child.xml using the RelativeLayout with childs (TextView for text and Button as Remove button)
Inflate the xml layout , add each views into your main_layout and
setonclicklistner to button.
when clicked on button , get the parent view from the clicked view and remove the view from main_layout.
this may help you.

Click event on EditText's drawableRight not working properly?

I need to open phone's contact book on the click of EditText's drawableRight. Click event on drawableRight is working fine But the problem is, when I click/touch on anywhere on EditText it is also execute click event and open contact list.
I take help for manage click event on drawableRight from here Please check this link.
I don't want to open contact list when I click on EditText, I only want to open it when I click drawableRight (image). So how solve this problem?
Here is my code:
EditText mobile_number;
mobile_number = (EditText)view.findViewById(R.id.mobile_number1);
mobile_number.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
final int DRAWABLE_LEFT = 0;
final int DRAWABLE_TOP = 1;
final int DRAWABLE_RIGHT = 2;
final int DRAWABLE_BOTTOM = 3;
if(event.getAction()==MotionEvent.ACTION_UP){
if(event.getRawX()>=(mobile_number.getRight()-mobile_number.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width()));
{
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent,PICK_CONTACT);
return true;
}
}
return true;
}
});
Here is my layout code:
<LinearLayout
android:layout_width="fill_parent"
android:id="#+id/linearlayout_two1"
android:layout_below="#+id/linearlayout_one1"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:layout_marginTop="20dp"
android:orientation="vertical"
>
<EditText
android:layout_width="300dp"
android:hint="Enter Your Mobile Number"
android:textSize="15sp"
android:id="#+id/mobile_number1"
android:paddingLeft="30dp"
android:layout_height="wrap_content"
android:drawableRight="#drawable/editbox_icon"
/>
</LinearLayout>
Instead of using getRawX(), try replacing that line with
if (event.getX() >= (mobile_number.getWidth() - mobile_number
.getCompoundDrawables()[DRAWABLE_RIGHT].getBounds().width())) {
EDIT: I believe View.getRight() returns the position of the right edge of the View relative to its parent, while TouchEvent.getRawX() returns the absolute X position on the screen.
EDIT AGAIN TO DEMONSTRATE MY POINT:
MainActivity.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.meremammal.www.edittextdrawable.MainActivity">
<!-- This layout is only here to demonstrate a situation that breaks the usage of getRawX() -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true">
<EditText
android:id="#+id/edit_text"
android:layout_width="400dp"
android:layout_height="wrap_content"
android:text="Hello World!"
android:drawableRight="#android:drawable/ic_input_add"/>
</RelativeLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
EditText mEditText;
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mEditText = (EditText) findViewById(R.id.edit_text);
mEditText.setOnTouchListener(new View.OnTouchListener() {
private float touchX = 0;
#Override
public boolean onTouch(View v, MotionEvent event) {
int drawableLeft = mEditText.getRight() - mEditText
.getCompoundDrawables()[2].getBounds().width();
// This detects the location of touch on ACTION_DOWN, but because it is
// using getRawX() and getRight() and the EditText's parent is not at the
// left of the screen, it will respond when clicked in the middle of the
// EditText. Instead, use getX() and EditText.getWidth()
if (event.getAction() == MotionEvent.ACTION_DOWN && event.getRawX() >= drawableLeft) {
touchX = event.getRawX();
return true;
} else if (event.getAction() == MotionEvent.ACTION_UP && touchX >= drawableLeft) {
Toast.makeText(mContext, "Clicked Button", Toast.LENGTH_SHORT).show();
touchX = 0;
return true;
} else {
return mEditText.onTouchEvent(event);
}
}
});
}
}
You don't have access to the right image as far my knowledge, unless you create custom EditText class. I suggest to use a RelativeLayout, with one editText and one imageView, and set OnClickListener over the image view as below:
<RelativeLayout
android:id="#+id/rlSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:drawable/edit_text"
android:padding="5dip" >
<EditText
android:id="#+id/txtSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/imgSearch"
android:background="#00000000"
android:ems="10"/>
<ImageView
android:id="#+id/imgSearch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="#drawable/btnsearch" />
</RelativeLayout>
Make a Linear layout with horizontal orientation and add a edit-text and image-view with proper weight..
Then Give on click for each item separately.....
Just chage the last return to false. Also you have to remove the comma ; at the end of if statement.

android Passing touch events of a Child view drawn outside of view clip bounds (ViewPager Page 1 to Page 2)

My Android ViewPager has set to draw views outside of the bounds (Clip bounds set to false) . I have a touch event listener on all the views displayed on the page. The custom view is displayed on the page 1, drawn outside of its clipping Bounds and overflows to the page 2. The touch event on the page 1 works fine. When scrolled to the second page, the remaining view is displayed. The issue is that the touch event on the custom view (added on the page 1) does not get called when clicked on the Page 2.
PageViewActivity.cs
ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setClipChildren(false);
mViewPager.setClipToPadding(false);
PageViewFragment.cs
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.page_layout, container, false);
setHasOptionsMenu(true);
View view1=(View)v.findViewById(R.id.view1);
view1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getActivity(), "View clicked",Toast.LENGTH_SHORT).show();
}
});return v;
}
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false" >
<View
android:id="#+id/view1"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_marginLeft="250dp"
android:layout_marginTop="20dp"
android:background="#ff0000" />
Fragment Layout - page_layout.xml
Any suggestions?
You have to manually detect the touch events, and see if it's coordinates lie within the bounds of the pages outside the bounds. So going off of what Tatarize states, before dispatching touch events to the pager, you should check if the event is within one of the pages of the view pager.
Here is example code, I'm only checking if the x lies within the bounds and not the y in childContains().
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
return pager.dispatchTouchEvent(event);
case MotionEvent.ACTION_UP:
int childCount = pager.getChildCount();
int x = (int) event.getX();
int y = (int) event.getY();
for (int i = 0; i < childCount; i++) {
final View child = pager.getChildAt(i);
if (childContains(child, x)) {
// delay the click minimally in-case
// callOnClick performs mods on the pager
//
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
child.callOnClick();
}
}, 100);
return true;
}
}
break;
}
return pager.dispatchTouchEvent(event);
}
int[] loc = new int[2];
private boolean childContains(View child, final int x) {
child.getLocationOnScreen(loc);
int x1_child = loc[0];
int x2_child = x1_child + child.getWidth();
int x0 = x;
boolean isInside = x0 >= x1_child && x0 < x2_child;
Log.v("childContains()", String.format("x: %s x1_child: %s x2_child: %s isInside: %s",
x0, x1_child, x2_child, String.valueOf(isInside)));
return isInside;
}
There’s a problem here. We can swipe only the middle view. This is because the touch events occur outside the ViewPagers bounds. We can override the onTouchEvent of the ViewPagerContainer and dispatch the events to the ViewPager to solve this.
private ViewPager mPager;
#Override
protected void onFinishInflate() {
mPager = (ViewPager) getChildAt(0);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
return mPager.dispatchTouchEvent(ev);
}
But the truth is you're better off using the more modern solutions to this stuff.
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.TabLayout
android:id="#+id/result_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/grey"
app:tabIndicatorColor="#color/colorPrimary"
app:tabMode="scrollable"
app:tabSelectedTextColor="#color/colorPrimary"
app:tabTextColor="#color/medium_grey" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
So tabbed layout and a properly setup viewpager. Though even this is going to be kind of obsolete once Google finishes up their Navigation bit in their Architecture Components.

Android - how to detect touch listener if view has click listener

I have basic layout with linear layout, ScrollView and ImageView.
ScrollView has registered onTouchListener and imageview onClicklistener.
If I tap on ImageView and I am pulling out of ImageView, I do not see log with "onclick".
If I tap out of imageView (on scrollView) and I am pulling somewhere, I see log with "on touch".
How can I catch onTouch event on my imageView, when I am pulling out of it?
Here is the code:
ImageView testButton = (ImageView) myView.findViewById(R.id.imageView1);
testButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d(tag, "onclick");
}
});
ScrollView scrollView = (ScrollView) myView.findViewById(R.id.scrollView1);
scrollView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(tag, "ontouch");
return false;
}
});
And here is xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical" >
<ScrollView
android:id="#+id/scrollView1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/com_facebook_blue"
android:scrollbarAlwaysDrawVerticalTrack="false" >
<LinearLayout
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/com_facebook_profile_picture_blank_square" />
</LinearLayout>
</ScrollView>
</LinearLayout>
Set an OnTouchListener to the ImageView as well. When you pull away the touch from view's touchable region it will fire a Touch event. OnClick wont be fired when the ontouch is cancelled(MotionEvent.ACTION_CANCEL).You should not consume the onTouch() therefore return false in onTouch()
Set this to your scroll view:
ScrollView mainScroll=(ScrollView) findViewById(R.id.your_scroll_view)
mainScroll.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mainScroll.setFocusable(true); //If you need this
mainScroll.setFocusableInTouchMode(true); //If you need this
Then your imageView onclick listener will be triggered. This code could also substantially affect other parts of your functionality. So please check the view once you implement this and revert if there are any screen jumps which occur.

Pass click event through the view android

I have frame layout:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" >
<LinearLayout
android:id="#+id/widgetView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="10dp"
android:gravity="center" >
</LinearLayout>
<LinearLayout
android:id="#+id/widgetOverlayFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false" >
</LinearLayout>
First layout contains widget layout, and second one is transparent and receives onLongClick for dragging method.That works, the problem is when i want to interact with widget, to click something, click event is taken by overlayFrame. How can i pass click event trough overlayFrame to widgetView?
EDIT:
Now I'm trying to attach GestureLister to overlayFrame LinearLayout, to somehow see difference between MotionEvent that represent single click and long click. The problem that I'm facing is that OnLongPress in gesture listener is always called whatever I do, single click or long click.
Is there an explanation for this behavior? Tnx!
In my case I added flag to layoutParams of my view, which should have passed a touch event under:
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
This way view will ignore all touches (like view with visibility GONE)
Instead of using GestureListener you can override the onTouchListener in this way.
This will call longPress when the timer runs out and if an up comes in between it will cancel the LongPress
CountDownTimer c;
long time=5000;
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
c= new CountDownTimer(5000, 1000) {
public void onTick(long millisUntilFinished) {
time=millisUntilFinished;
}
public void onFinish() {
Log.i("","LONG PRESS");
}}.start();
break;
case MotionEvent.ACTION_UP:
if (time>0) {
Log.i("example","short click");
c.cancel();
}
break;
}
return true;
}
Maybe setting the overlay's attribute android:focusable="false" or android:focusableInTouchMode="false" would be enough.
You could also make your own overlay widget and override its onInterceptTouchEvent method to return false always.
public class NotTouchableLinearLayout extends LinearLayout {
// Override constructors
// ...
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
Instead of setting a GestureListener on the top layout, you should create your own class that extends LinearLayout and to override it's onTouchEvent method.
There you can implement the logic of long click \ short click etc.
The click events will first be sent to the widget layout, and only if it doesn't handle them (hence it's onTouchEvent returns false), you will get them on the top layout.
edit:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp" >
<LinearLayout
android:id="#+id/widgetView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="10dp"
android:gravity="center" >
</LinearLayout>
<com.example.touchtesting.MyLinearLayout
android:id="#+id/widgetOverlayFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false" >
</com.example.touchtesting.MyLinearLayout>
</FrameLayout>
change the com.example.touchtesting to the name of your package.
and this is the class:
public class MyLinearLayout extends LinearLayout{
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
private long startClick = 0;
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startClick = ev.getEventTime();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (ev.getEventTime() - startClick < 500) {
Log.i("example","short click");
}
else {
Log.i("example","long click");
}
break;
}
return true;
}
}
To get the long clicks to pass through the widgetView LinearLayout add android:longClickable="true". (For ordinary clicks add android:clickable="true")
So widgetView becomes:
<LinearLayout
android:id="#+id/widgetView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_margin="10dp"
android:gravity="center"
android:longClickable="true">
</LinearLayout>

Categories

Resources