sliding up panel - thin line sliding panel under google mapfragment - android

I made slidinguppanel using this repository https://github.com/dlukashev/AndroidSlidingUpPanel-foursquare-map-demo
However, it contains one bug which is not covered anywhere.
When I touch anywhere to expand panel (listview) works well, but while I'm trying to expand it by holding a top of a list view (blue line on screen2) panel hide under the map (framelayout) (screen3)
How it's even possible that this blue line hiding panel under mapfragment and rest of listview expand it well?
Any ideas why? Please give me just a hint how to fix it?
Please look at the screen:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<org.sothree.slidinguppanel.SlidingUpPanelLayout
android:id="#+id/slidingLayout"
android:gravity="bottom"
app:shadowHeight="0dp"
app:paralaxOffset="#dimen/paralax_offset"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<FrameLayout
android:gravity="top"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/button">
<RelativeLayout
android:id="#+id/mapContainer"
android:layout_width="fill_parent"
android:layout_height="497dp"/>
</FrameLayout>
<RelativeLayout
android:id="#+id/slidingContainer"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/button">
<View
android:id="#+id/transparentView"
android:visibility="gone"
android:layout_width="fill_parent"
android:layout_height="#dimen/map_height"
android:layout_alignParentTop="true"/>
<ListView
android:id="#+id/listView1"
android:cacheColorHint="#android:color/white"
android:drawSelectorOnTop="true"
android:dividerHeight="#dimen/divider_height"
android:divider="#android:color/darker_gray"
android:background="#android:color/transparent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#id/transparentView"
android:smoothScrollbar="true"
android:layout_marginTop="0dp"/>
</RelativeLayout>
</org.sothree.slidinguppanel.SlidingUpPanelLayout>
</RelativeLayout>

You need to override ListView
public class LockableListView extends ListView {
private boolean mScrollable = true;
public LockableListView(Context context) {
super(context);
}
public LockableListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LockableListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setScrollingEnabled(boolean enabled) {
mScrollable = enabled;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// if we can scroll pass the event to the superclass
if (mScrollable) {
return super.onTouchEvent(ev);
}
// only continue to handle the touch event if scrolling enabled
return mScrollable; // mScrollable is always false at this point
default:
return super.onTouchEvent(ev);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Don't do anything with intercepted touch events if
// we are not scrollable
if (!mScrollable) {
return false;
} else {
return super.onInterceptTouchEvent(ev);
}
}
}
Then put disable scrolling when needed
private void collapseMap() {
mSpaceView.setVisibility(View.VISIBLE);
mTransparentView.setVisibility(View.GONE);
if (mMap != null && mLocation != null) {
mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(mLocation, 11f), 1000, null);
}
mListView.setScrollingEnabled(true);
}
private void expandMap() {
mSpaceView.setVisibility(View.GONE);
mTransparentView.setVisibility(View.INVISIBLE);
if (mMap != null) {
mMap.animateCamera(CameraUpdateFactory.zoomTo(14f), 1000, null);
}
mListView.setScrollingEnabled(false);
}
I pushed this changes to GitHub https://github.com/dlukashev/AndroidSlidingUpPanel-foursquare-map-demo/commit/7b869394e9d197e6f56a833804426577dcb8458a
Enjoy

Related

How to swipe ViewPager while the content is being scrolled?

I am able to implement TabLayout with ViewPager nicely but when the content inside the ViewPager is being scrolled (the deceleration animation), I cannot swipe left and right to change to other fragments inside ViewPager. I have to wait until the scrolling animation stops and then swipe.
Below is some of my code snippets.
I have a simple activity_main.xml layout like below.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbarHome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"/>
<LinearLayout
android:id="#+id/mainContainerLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
</LinearLayout>
<android.support.design.widget.BottomNavigationView
android:id="#+id/btmNavView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
app:menu="#menu/menu_main" />
</LinearLayout>
I then inflate a fragment containing TabLayout and ViewPager into the LinearLayout in the middle of the activity_main.xml. This layout can be seen below:
<LinearLayout 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:orientation="vertical">
<com.pchatanan.sontana.custom_views.AppTabLayout
android:id="#+id/contactTabLayout"
app:tabMode="fixed"
android:layout_height="wrap_content"
android:layout_width="match_parent"
style="#style/AppTabLayout"/>
<android.support.v4.view.ViewPager
android:id="#+id/contactViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
The logic inside my fragment is below:
fragmentArray = new Fragment[]{new SimpleFragment(), new SimpleFragment(), new SimpleFragment()};
titleArray = new String[]{"fragment1", "fragment2", "fragment3"};
contactPagerAdapter = new AppPagerAdapter(getChildFragmentManager(), fragmentArray, titleArray);
contactViewPager.setAdapter(contactPagerAdapter);
contactViewPager.setOffscreenPageLimit(fragmentArray.length - 1);
contactTabLayout.setupWithViewPager(contactViewPager);
Use this instead defualt ViewPager.
Detect when ScrollView or RecyclerView is scrolling. Then call
viewPager.setPagingEnabled(pagingEnable);
If pagingEnable
public class CustomViewPager extends ViewPager {
private boolean isPagingEnabled = true;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onTouchEvent(event);
}
public boolean onInterceptTouchEvent(MotionEvent event) {
return this.isPagingEnabled && super.onInterceptTouchEvent(event);
}
public void setPagingEnabled(boolean b) {
this.isPagingEnabled = b;
}
}
Update:
You can do reverse to like you can disable ScrollView scroll when ViewPager is swiping
mScrollView.requestDisallowInterceptTouchEvent(true);
Similar to what suggested by #Khemraj, the problem is the touch is not intercepted by ViewPager. It is only intercepted by the ScrollView. To fix this, we should allow ViewPage to intercept the touch when scrolling:
scrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View view, int i, int i1, int i2, int i3) {
viewPager.requestDisallowInterceptTouchEvent(false);
}
});
A better implementation is to make use of CallBackListener onto the fragment containing the scrollView.

ViewPager : swipe only from a particular view

I have a created a custom viewpager, and i would like the user to swipe and change pages only from a part of the screen.
Every page has a linearlayout at the bottom with some text, and i would like to swipe only from there, not from the hole screen.
Is that possible?
This is my custom viewpager class:
public class MyViewPager extends ViewPager {
private boolean mSwipable = true;
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mSwipable ? super.onInterceptTouchEvent(event) : false;
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return mSwipable ? super.onTouchEvent(event) : false;
}
public boolean isSwipable() {
return mSwipable;
}
public void setSwipable(boolean swipable) {
mSwipable = swipable;
}
}
and this is the view of a page:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:clipChildren="false"
android:clipToPadding="false"
android:fillViewport="true"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/fragment_search">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/bottomLayout"
android:layout_marginBottom="#dimen/bottom_bar_height">
//show some stuff here
</LinearLayout>
<LinearLayout
android:id="#+id/bottomMenu"
android:layout_width="match_parent"
android:layout_height="#dimen/bottom_bar_height"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:orientation="horizontal">
// this is my footer, where i need to change the pages by swipe
</LinearLayout>
</RelativeLayout>
Follow this question in order to be able to disable swiping at will How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?
And combine that with your SliderAdapter in order to control which pages will be swipeable or not.
If you followed the link above, on your subclass of ViewPager, you can add some GestureDetector on onTouchEvent(MotionEvent event) and feed it with your event, like Android: How to handle right to left swipe gestures
By doing this, you will now have some onSwipeRight and manage there your logic, delegating to the adapter the question if the page should be swiped or not, or where to go next.

Keyboard hides the input field in WebView

I have a layout:
<LinearLayout 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"
tools:context=".StreamActivity"
android:orientation="vertical">
<FrameLayout
android:id="#+id/streamLayout"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<SurfaceView
android:id="#+id/surface"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start">
</SurfaceView>
</FrameLayout>
<WebView
android:id="#+id/web_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="start"/>
FrameLayout for a video player. WebView is a chat.
When I begin to type text into the chat, the keyboard hides input field.
I tried experimenting with android: windowSoftInputMode, but it does not work for me. The problem with chat, it is written on Angular and resizing WebView does not change the size of the chat, it must be done manually like webView.loadUrl("javascript: $('section.content-window:first').css('height', '" + finalSize + "px');");
I have a listener that is triggered when the keyboard is shown and hidden.
I would like to manually change the size of the chat when the keyboard is showed, but it does not work well because when I change the size of chat it loses focus and the keyboard hidden.
I also thought to put the content of the Activity in ScrollView. If override OnTouchListener this will lock scroll by user, but I will still be able to scroll from code. So, I wanted if the keyboard is shown then scroll content of the Activity so it would be visible the entire chat. I think this will work, but not good because it will lock the scrolling in WebView.
Advise how to fix this problem with the keyboard and chat?
I found a solution:
<ScrollView ...
<LinearLayout ...
...
<com.package.TouchyWebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/webView"/>
...
</LinearLayout>
</ScrollView>
and do like this
package com.mypackage.common.custom.android.widgets
public class TouchyWebView extends WebView {
public TouchyWebView(Context context) {
super(context);
}
public TouchyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchyWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent event){
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
}
and
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
and to scroll I use code like this
final View activityRootView = findViewById(R.id.main_layout);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
boolean isOpen = false;
#Override
public void onGlobalLayout() {
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
if (!isOpen) {
scrollView.scrollBy(0, heightDiff);
isOpen = true;
}
} else {
if (isOpen) {
scrollView.scrollBy(0, -heightDiff);
isOpen = false;
}
}
}
});

requestDisallowInterceptTouchEvent for Scrollview

I have a StreetViewPanoramaView inside a linearlayout inside a scrollview:
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollview">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/linear">
<com.google.android.gms.maps.StreetViewPanoramaView
android:id="#+id/street_view_panorama"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<other views - textviews etc>
</LinearLayout>
</ScrollView>
The StreetViewPanoramaView allows a user to move the streetview camera up and down and left and right. I want the scrollview to stop intercepting the user touch events when the user is moving the camera. Currently, if the user moves the camera in the StreetViewPanoramaView, the scrollview intercept the touch and moves the scrollview instead.
I tried this code from https://mobiarch.wordpress.com/2013/11/21/prevent-touch-event-theft-in-android/ but its doesn't seem to be working (scrollview is still taking the touch events):
mStreetViewPanoramaView = (StreetViewPanoramaView) findViewById(R.id.street_view_panorama);
LinearLayout.LayoutParams streetViewLp =
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, displaymetrics.widthPixels/3);
mStreetViewPanoramaView.setLayoutParams(streetViewLp);
disableTouchTheft(mStreetViewPanoramaView);
public static void disableTouchTheft(View view) {
view.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
view.getParent().getParent().requestDisallowInterceptTouchEvent(true);
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
view.getParent().getParent().requestDisallowInterceptTouchEvent(false);
break;
}
return false;
}
});
}
EDIT:
Things I have tried:
I have made a custom view and imported the code dispatchTouchEvent into my activity code:
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
int[] loc = {0, 0};
mStreetViewPanoramaView.getLocationOnScreen(loc);
Rect rect = new Rect(loc[0], loc[1] , loc[0] + mStreetViewPanoramaView.getWidth(), loc[1] + mStreetViewPanoramaView.getHeight());
if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
Log.e("stretview", "dispatched");
return mStreetViewPanoramaView.dispatchTouchEvent(event);
/* return true;*/
}else{
//Continue with touch event
return super.dispatchTouchEvent(event);
}
}
public class CustomStreetViewPanoramaView extends StreetViewPanoramaView {
public CustomStreetViewPanoramaView(Context context) {
super(context);
}
public CustomStreetViewPanoramaView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomStreetViewPanoramaView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomStreetViewPanoramaView(Context context, StreetViewPanoramaOptions options) {
super(context, options);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return false; // Do not intercept touch event, let the child handle it
}
}
The code appears to half-work - it appears that the StreetViewParnoramaView will obtain the touch events for the top half of the view but the bottom half does not obtain any touch events.
My full layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:id="#+id/container"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/scrollview">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/linearlayout">
<com.example.simon.customshapes.CustomStreetViewPanoramaView
android:id="#+id/street_view_panorama"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="500dp"
android:id="#+id/card"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello card"
android:layout_gravity="center" />
</android.support.v7.widget.CardView>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Save panorama"
android:padding="8dp"
android:id="#+id/savepano"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
</ScrollView>
</LinearLayout>
The answer of Johann is the right path but still not working - this one will work
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (streetView != null) {
streetView.getGlobalVisibleRect(rect);
if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
event.offsetLocation(-rect.left, -rect.top);
streetView.dispatchTouchEvent(event);
return true;
} else {
//Continue with touch event
return super.dispatchTouchEvent(event);
}
} else {
return super.dispatchTouchEvent(event);
}
}
dispatchTouchEvent of the activity and move the event after offsets it to the streetView
Can you try the following...
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
int[] loc = {0, 0};
mStreetViewPanoramaView.getLocationOnScreen(loc);
Rect rect = new Rect(loc[0], loc[1] , loc[0] + mStreetViewPanoramaView.getWidth(), loc[1] + mStreetViewPanoramaView.getHeight());
if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
mStreetViewPanoramaView.dispatchTouchEvent(event);
return true;
}else{
//Continue with touch event
return super.dispatchTouchEvent(event);
}
}
This hopefully will check if the touch was on the panoramaview and handle accordingly.

android ImageView's onTouch and onClick nevet get called?

create a custom view for color picker that contains image and I'm going to take a color from this image on touch bot neither onTouch(View v, MotionEvent ev) nor onClick(View v) is called.
So here is my view class:
public class ChangeColor extends RelativeLayout {
public ChangeColor(Context context) { super(context); init(); }
public ChangeColor(Context context, AttributeSet attrs) { super(context, attrs); init(); }
private void init(){
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.change_color, this);
}
#Override
protected void onFinishInflate() {
super.onFinishInflate();
ImageView iv = (ImageView)findViewById(R.id.colorScaleImageView);
final Bitmap bitmap = ((BitmapDrawable) iv.getDrawable()).getBitmap();
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Log.d("ImageView", "onClick();");
}
});
iv.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent ev) {
Log.d("ChangeColor", "onTouch();");
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
int c = bitmap.getPixel((int)ev.getX(), (int)ev.getY());
SettingsManager.setColor(c);
Log.d("ChangeColor", "" + c);
return false;
default:
return true;
}
}
});
}
}
and layout xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/colorScaleImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/seekBar1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:clickable="true"
android:layout_gravity="center_horizontal"
android:src="#drawable/background_color" />
<SeekBar
android:id="#+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/textView1"
android:layout_alignParentLeft="true"
android:focusable="false"
android:maxHeight="8dp"
android:minHeight="8dp"
android:paddingLeft="7dp"
android:paddingRight="7dp"
android:progressDrawable="#drawable/seekbar_progress"
android:thumb="#drawable/seekbar_thumb_"
android:thumbOffset="7dp" />
</RelativeLayout>
So no one log message appear in LogCat.
P.S. I saw few similar questions on SO but they did not helped me.
P.P.S. This view is used in fragment and fragment is used in Activity. I added a fullscreen view in that activity with OnClickListener in order to see if clicks go to the parent view and I can see Log message from that background view only I tap outside the image and no message if I tap on image.
Thanks.
You have extended the relative layout but are not calling it in this example.
In the XML you should implement the class you developed instead of RelativeLayout
try
<?xml version="1.0" encoding="utf-8"?>
<**namespace**.ChangeColor xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/colorScaleImageView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="#+id/seekBar1"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:clickable="true"
android:layout_gravity="center_horizontal"
android:src="#drawable/background_color" />
</**namespace**.ChangeColor>
**EDIT
It was correct the first time. To implement it you'll have to attach ChangeColor to another layout, it cannot be called in the layout that it is attempting to inflate when it's called. Ex. ChangeColor inflates change_color.xml, you cannot have the tag NAMESPACE.ChangeColor called in the layout that ChangeColor.init() is inflating.

Categories

Resources