I have a view and I want to show it when I click on button/layout and hide it when I touch somewhere else. How can I do it?
I wrote some code in dispatchTouchEvent(Motion Event) and it's working. But, I think there must be another way to do it.
You can fill the outside of your RecyclerView with another clickable view and implement setOnTouchListener method for that view. Here's an example:
Let's say we have got RecyclerView at the top of our RelativeLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:clickable="true"
android:focusable="true">
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scrollbars="vertical" />
<!--View below is just to fill the remaining space. We will use this view to catch outside touch-->
<View
android:id="#+id/outside_detector"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/recyclerView"
android:clickable="true"
android:focusable="true"/>
</RelativeLayout>
And we want to hide and show our recyclerview when we click outside of RecyclerView:
((View) findViewById(R.id.outside_detector)).setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
if(arg1.getAction() == MotionEvent.ACTION_DOWN){
if(recyclerView.getVisibility() == View.VISIBLE){
recyclerView.setVisibility(View.INVISIBLE);
}else{
recyclerView.setVisibility(View.VISIBLE);
}
}
return true;
}
});
If you want to show recyclerview on button click, then just write recyclerView.setVisibility(View.VISIBLE) method inside button ClickListener!
Hope this helps!
Related
I want to scroll the whole layout above keyboard but its not working. I was able to scroll manually but want it to scroll
programatically when a user sets focus on the edit text.
Please help me. Thanks in advance
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollView"
android:fillViewport="true"
android:paddingBottom="?attr/actionBarSize">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
......
edit_text_code.setOnFocusChangeListener { view, hasFocus ->
if (hasFocus) {
scrollView.post {
scrollView.fullScroll(NestedScrollView.FOCUS_DOWN)
}
}
}
Method 1:
First get the x/y coordinates of your Edittext using View.getLocationOnScreen (int[] location) ( After the method returns, the array contains the x and y location in that order)
Then do :
scrollView.scrollTo(x, y);
If above method doesn't work try below method :
Method 2:
edit_text_code.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View view, MotionEvent event) {
// put your edit text id below
if (view.getId() ==R.id.DwEdit) {
view.getParent().requestDisallowInterceptTouchEvent(true);
switch (event.getAction()&MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_UP:
view.getParent().requestDisallowInterceptTouchEvent(false);
break;
}
}
return false;
}
});
XML Code :
<EditText
android:id="#+id/DwEdit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minLines="10"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical"
android:overScrollMode="always"
android:inputType="textCapSentences">
</EditText>
I am using a RecyclerView with a LinearLayoutManager to populate an ArrayList of objects. What I need is how to implement the onFocus event when I change the focus from item to item? onClick event works fine, but the onFocus event has no effect.
XML:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/listchannels"
android:layout_width="600dp"
android:layout_height="560dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:layout_marginLeft="30dp">
<android.support.v7.widget.RecyclerView
android:id="#+id/channelList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
android:focusable="true"
android:focusableInTouchMode="true"/>
</FrameLayout>
My coding implementation of onFocus within the ViewHolder class in the ListAdapter:
#Override
public void onFocusChange(View v, boolean hasFocus) {
int position = getAdapterPosition();
if(hasFocus) {
Toast.makeText(this.ctx, "Position : " + position, Toast.LENGTH_SHORT).show();
}
}
The onFocus event here has no effect, it doesn't work. Is it possible to implement the onFocus event on a RecyclerView?
Check if this helps. I found somewhat similar to your issue.
https://stackoverflow.com/a/33190656/2779404
If not, let me try providing another approaches.
AndroidSlidingUpPanel
Here, I am using slidingup panel library. You can see both the panel and listview in the following screen. What i am trying to do is to hide the panel if i click outside the panel(Dim Area). Instead it is clicking on the listview in the above layout. How can i achieve this?
Here is the XML,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.voucher.point.activity"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<!-- sothree:dragView="#+id/dragView" -->
<com.sothree.slidinguppanel.SlidingUpPanelLayout
xmlns:sothree="http://schemas.android.com/apk/res-auto"
android:id="#+id/sliding_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom"
app:fadeColor="#color/transparent"
sothree:panelHeight="40dip"
sothree:paralaxOffset="200dp" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/white"
android:orientation="vertical" >
<ListView
android:id="#+id/offersList"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="none"
android:visibility="gone" >
</ListView>
</LinearLayout>
<include
android:id="#+id/bottom_menu"
android:layout_width="fill_parent"
android:layout_height="270dip"
layout="#layout/side_menu" />
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
Can i do like this?
With the version 3.3.0 and later, it's possible to do that in the following way
final SlidingUpPanelLayout slidingUpPanelLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
slidingUpPanelLayout.setFadeOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
});
source
I believe you have fixed your problem but for others who has same requirement I added another View on top of my map (in xml layout) and set it's touch click-ability.
So my xml file is like this:
<com.sothree.slidinguppanel.SlidingUpPanelLayout
android:id="#+id/sliding_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/booking_confirm_layout"
android:gravity="bottom"
app:umanoFadeColor="#color/black_75_percent"
app:umanoOverlay="true"
app:umanoPanelHeight="111dp"
app:umanoShadowHeight="0dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/map_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="96dp" />
<View
android:id="#+id/mapCover"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/transparent"/>
</FrameLayout>
<LinearLayout>
.
.
.
</LinearLayout>
</com.sothree.slidinguppanel.SlidingUpPanelLayout>
And in the code:
this.mMapCover = findViewById(R.id.mapCover);
this.mMapCover.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
if (mSlidingPanel.getPanelState() != PanelState.COLLAPSED)
{
mSlidingPanel.setPanelState(PanelState.COLLAPSED);
return true;
}
return false;
}
});
//to hide when you touch overlay
mLayout.setFadeOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
});
to hide it totaly
mLayout.setFadeOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mLayout.setPanelState(SlidingUpPanelLayout.PanelState.HIDDEN);
}
});
you can add a onClickListener or onTouchListener to the outside panel and ontouch or oncick call slidingPanelLayout.expandPane(0)
findViewById(R.id.bg_panel).setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
slidingPanelLayout.expandPane(0);
return false;
}
The answered code didn't work for me. Unfortunately this event does not capture a click on part of my UI.
So for doing that, set an id for main content (first child of SlidingUpPanelLayout) and call this:
findViewById(R.id.main_content).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(slidingUpPanelLayout.getPanelState() != SlidingUpPanelLayout.PanelState.COLLAPSED){
slidingUpPanelLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
}
}
});
Your slidingUp panel contain whole screen then how you detect the click on outside of screen. If you are targeting it to only for "HideMenu" and "ShowMenu" then it is possible to do.
Otherwise with Full Screen SlidingUp Panel you can able to hide it by click back android button or any click event on the panel it self.
Let me know if my answer not resolve your problem.
Enjoy Coding... :)
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.
I have one of the new MapFragments in a ScrollView. Actually it's a SupportMapFragment, but anyway. It works, but there are two problems:
When scrolled, it leaves a black mask behind. The black covers exactly the area where the map was, except for a hole where the +/- zoom buttons were. See screenshot below. This is on Android 4.0.
The view doesn't use requestDisallowInterceptTouchEvent() when the user interacts with the map to prevent the ScrollView intercepting touches, so if you try to pan vertically in the map, it just scrolls the containing ScrollView. I could theoretically derive a view class MapView and add that functionality, but how can I get MapFragment to use my customised MapView instead of the standard one?
Applying a transparent image over the mapview fragment seems to resolve the issue. It's not the prettiest, but it seems to work. Here's an XML snippet that shows this:
<RelativeLayout
android:id="#+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="300dp" >
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.MapFragment"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<ImageView
android:id="#+id/imageView123"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/temp_transparent" />
</RelativeLayout>
For me adding a transparent ImageView did not help remove the black mask completely. The top and bottom parts of map still showed the black mask while scrolling.
So the solution for it, I found in this answer with a small change.
I added,
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
to my map fragment since it was vertical scrollview. So my layout now looked this way:
<RelativeLayout
android:id="#+id/map_layout"
android:layout_width="match_parent"
android:layout_height="300dp">
<fragment
android:id="#+id/mapview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
android:name="com.google.android.gms.maps.MapFragment"/>
<ImageView
android:id="#+id/transparent_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#color/transparent" />
</RelativeLayout>
To solve the second part of the question I set requestDisallowInterceptTouchEvent(true) for my main ScrollView. When the user touched the transparent image and moved I disabled the touch on the transparent image for MotionEvent.ACTION_DOWN and MotionEvent.ACTION_MOVE so that map fragment can take Touch Events.
ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scrollview);
ImageView transparentImageView = (ImageView) findViewById(R.id.transparent_image);
transparentImageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
mainScrollView.requestDisallowInterceptTouchEvent(true);
// Disable touch on transparent view
return false;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
mainScrollView.requestDisallowInterceptTouchEvent(false);
return true;
case MotionEvent.ACTION_MOVE:
mainScrollView.requestDisallowInterceptTouchEvent(true);
return false;
default:
return true;
}
}
});
This worked for me. Hope it helps you..
This probably has its roots in the same place at causes the problem in this question. The solution there is to use a transparent frame, which is a little lighter weight than a transparent image.
Done after lots of R&D:
fragment_one.xml should looks like:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollViewParent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="400dip" >
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<View
android:id="#+id/customView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#android:color/transparent" />
</RelativeLayout>
<!-- Your other elements are here -->
</LinearLayout>
</ScrollView>
Your Java class of FragmentOne.java looks like:
private GoogleMap mMap;
private MapView mapView;
private UiSettings mUiSettings;
private View customView
onCreateView
mapView = (MapView) rootView.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (mapView != null) {
mMap = mapView.getMap();
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mUiSettings = mMap.getUiSettings();
mMap.setMyLocationEnabled(true);
mUiSettings.setCompassEnabled(true);
mUiSettings.setMyLocationButtonEnabled(false);
}
scrollViewParent = (ScrollView)rootView.findViewById(R.id.scrollViewParent);
customView = (View)rootView.findViewById(R.id.customView);
customView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
// Disallow ScrollView to intercept touch events.
scrollViewParent.requestDisallowInterceptTouchEvent(true);
// Disable touch on transparent view
return false;
case MotionEvent.ACTION_UP:
// Allow ScrollView to intercept touch events.
scrollViewParent.requestDisallowInterceptTouchEvent(false);
return true;
case MotionEvent.ACTION_MOVE:
scrollViewParent.requestDisallowInterceptTouchEvent(true);
return false;
default:
return true;
}
}
});
I used this structures and I overcame the problem.
I used a container view for maps fragment.
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="Another elements in scroll view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<com.erolsoftware.views.MyMapFragmentContainer
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="250dp">
<fragment
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:id="#+id/eventMap"
tools:context="com.erolsoftware.eventapp.EventDetails"
android:name="com.google.android.gms.maps.SupportMapFragment"/>
</com.erolsoftware.views.MyMapFragmentContainer>
<TextView
android:text="Another elements in scroll view2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
The container class:
public class MyMapFragmentContainer extends LinearLayout {
#Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN)
{
ViewParent p = getParent();
if (p != null)
p.requestDisallowInterceptTouchEvent(true);
}
return false;
}
public MyMapFragmentContainer(Context context) {
super(context);
}
public MyMapFragmentContainer(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyMapFragmentContainer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
No need to struggle with customScrollViews and transparent layout files. simply use lighter version of google map and your issue will be resolved.
map:liteMode="true"
add above property inside map fragment in your layout file. and issue will be fixed.
For the second part of the question - you can derive a fragment class from SupportMapFragment, and use that in your layout instead. You can then override Fragment#onCreateView, and instantiate your custom MapView there.
If that does not work, you can always create your own fragment - then you just need to take care of calling all the lifecycle methods yourself (onCreate, onResume, etc). This answer has some more details.
<ScrollView
android:layout_width="match_parent"
::
::
::
<FrameLayout
android:id="#+id/map_add_business_one_rl"
android:layout_width="match_parent"
android:layout_height="100dp"
>
<fragment
android:id="#+id/map"
android:name="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="-100dp"
android:layout_marginBottom="-100dp"
/>
</FrameLayout>
::
::
::
</ScrollView>