Click ImageView on Specific Location - android

I have an imageView and when I need to let the user click only on a specific location (the white space) as shown in the image below, any suggestion?
here is my xml
<RelativeLayout
android:id="#+id/lockRelativeLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="5dp"
>
<ImageView
android:id="#+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/image" />
</RelativeLayout>
and here is the code
private View.OnTouchListener imageViewOnClickListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int x = (int)event.getX();
int y = (int)event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN){
//here i want if he clicked on specific location to go to another activity
Intent intent = new Intent(context, ViewerActivity.class);
context.startActivity(intent);
}
return true;
}
};
I don't know if i should use onClick or onTouchClick!!

You could implement the OnTouchListener.
anImageView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
//Check between +- 10px jsu tto have some are to hit
int centerX = (v.getWidth() /2);
if(event.getX() > centerX - 10)
&& event.getX() < centerX + 10)){
//Do your magic
}
}
return true;
}
});
The event contains the coordinates for the event.
Then you can compare that either to the the boundaries you set up or get the correct pixel from the image an check if it is white.

I would advise to put another transparent control in your relative layout on top of ImageView with paddings you need, and subscribe to its onClick event. This way you can be sure only proper area was clicked.

What i did is I used two images One for Show your Image and Secound is show only Some Part of that where you want to click
Please Note My Secound Image is my transparent image. So use one1 as a transparent image. And use its Click Event.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/ic_launcher" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#xml/shape"
android:gravity="center" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/one1" />
</LinearLayout>
now create xml and create shape.xml file which is give to Linearlayout
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="20dip" />
<stroke
android:width="100dip"
android:color="#A0ffffff" />

i found a solution by myself: thanks all for replying:
private View.OnTouchListener imageViewOnClickListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent event) {
int x = (int) event.getX();
if (173 <= x && x <= 671) {
Intent intent = new Intent(context, NextActivity.class);
context.startActivity(intent);
}
return true;
}
};

Related

Why Android EditText have to click the second time to trigger the event?

The xml file:
<EditText
android:drawableLeft="#drawable/icon_lock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:id="#+id/et_pwd"
android:drawableRight="#drawable/icon_closeeye_32"
style="#style/editText_base"
android:hint="#string/pwd_input"/>
Outside is LinearLayout
The code:
private boolean isTouch = false;
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN :
Drawable drawableRight = etPwd.getCompoundDrawables()[2];
if(drawableRight == null && event.getAction() != MotionEvent.ACTION_UP) {
return false;
}
if (event.getX() > etPwd.getWidth()
- etPwd.getPaddingRight()
- drawableRight.getIntrinsicWidth()){
Drawable drawableLeft = getResources().getDrawable(R.drawable.icon_lock);
drawableLeft.setBounds(0, 0, drawableLeft.getMinimumWidth(), drawableLeft.getMinimumHeight());
if (isTouch) {
etPwd.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
Drawable drawableOpenEye = getResources().getDrawable(R.drawable.icon_openeye_32);
drawableOpenEye.setBounds(0, 0, drawableOpenEye.getMinimumWidth(), drawableOpenEye.getMinimumHeight());
etPwd.setCompoundDrawables(drawableLeft, null, drawableOpenEye, null);
} else {
etPwd.setTransformationMethod(PasswordTransformationMethod.getInstance());
Drawable drawableCloseEye = getResources().getDrawable(R.drawable.icon_closeeye_32);
drawableCloseEye.setBounds(0, 0, drawableCloseEye.getMinimumWidth(), drawableCloseEye.getMinimumHeight());
etPwd.setCompoundDrawables(drawableLeft, null, drawableCloseEye, null);
}
isTouch = !isTouch;
etPwd.setSelection(etPwd.getText().toString().length());
}
break;
case MotionEvent.ACTION_MOVE :
break;
case MotionEvent.ACTION_UP :
break;
}
return false;
}
Now! Did not respond for the first time , Click the second time to show the icon open , to show / hide the password.
And i`ve already implements View.OnTouchListener , find the relevant controls to do the click event . Help me , thanks!
You need to either change
private boolean isTouch = false;
to true.
private boolean isTouch = true;
Or you need to switch the blocks inside the if statement around.
The reason for this is because the first time it goes through the codeblock, isTouch is false, and it sets the transformation to password - which it's already in! Now isTouch is set to true, and the second time it goes through the expected code block to show the password.
Try this,
XML:
<RelativeLayout
android:id="#+id/relative01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/et_username"
android:background="#drawable/selector"
android:padding="10dp">
<com.mycalculator.utils.CustomEditText
android:id="#+id/et_pwd"
android:layout_width="fill_parent"
android:layout_height="42dp"
android:layout_toStartOf="#+id/iv_show_pwd"
android:background="#null"
android:hint="#string/Password"
android:inputType="textPassword"
android:singleLine="true"
android:textColor="#color/colorBlack"
/>
<ImageView
android:id="#+id/iv_show_pwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="3dp"
android:layout_marginStart="3dp"
android:src="#drawable/icon_closeeye_32" />
</RelativeLayout>
selector:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<corners android:radius="6dp" />
<gradient
android:angle="90" />
<solid android:color="#color/colorWhite"/>
<stroke
android:width="1dp"
android:color="#color/Gray" />
</shape>
JAVA:
EditText et_pwd = (EditText) findViewById(R.id.et_pwd);
ImageView iv_show_pwd = (ImageView) findViewById(R.id.iv_show_pwd);
iv_show_pwd.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (et_pwd.getTransformationMethod() == PasswordTransformationMethod.getInstance()) {
et_pwd.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
iv_show_pwd.setImageResource(R.drawable.ic_visible);
} else {
et_pwd.setTransformationMethod(PasswordTransformationMethod.getInstance());
iv_show_pwd.setImageResource(R.drawable.ic_invisible);
}
}
});

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.

How can I implement a chrome like "auto-hide navigation" for my Android app?

In Chrome, the address bar will be hidden/shown when user swipes up/down the content.
Can I implement the similar logic to my app?
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
tools:ignore="MergeRootFrame">
<WebView
android:id="#+id/my_webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
I wonder if there is anything I can do by the following code, so that the ActionBar will be hidden/shown when user swipe up/down the webView.
WebView webView = (WebView) findViewById(R.id.my_webview);
webView.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch (View v, MotionEvent event) {
webView.onTouchEvent(event);
}
});
This pattern is called Quick Return.
Start with this blog post.
However, it is worthwhile reading this when considering its use.
First you need layout with alignParentBottom and match_parent WebView and some bar at top:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffff" >
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true" />
<RelativeLayout
android:id="#+id/actionBar"
android:layout_width="match_parent"
android:layout_height="50dp" >
<TextView
android:id="#+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="TextView" />
</RelativeLayout>
</RelativeLayout>
Then you need code:
1) Declare and set some internal values and resize WebView to make it below our bar:
private int baseHeight;
private int webViewOnTouchHeight;
private int barHeight;
private float heightChange;
private float startEventY;
barHeight = actionBar.getMeasuredHeight();
baseHeight = getView().getMeasuredHeight();
webView.getLayoutParams().height = webView.getMeasuredHeight() - barHeight;
webView.requestLayout();
webView.setOnTouchListener(listener);
2) Create resize method. Here we check new height with limits of screen top and bar height
private boolean resizeView(float delta) {
heightChange = delta;
int newHeight = (int)(webViewOnTouchHeight - delta);
if (newHeight > baseHeight){ // scroll over top
if (webView.getLayoutParams().height < baseHeight){
webView.getLayoutParams().height = baseHeight;
webView.requestLayout();
return true;
}
}else if (newHeight < baseHeight - barHeight){ // scroll below bar
if (webView.getLayoutParams().height > baseHeight - barHeight){
webView.getLayoutParams().height = baseHeight - barHeight;
webView.requestLayout();
return true;
}
} else { // scroll between top and bar
webView.getLayoutParams().height = (int)(webViewOnTouchHeight - delta);
webView.requestLayout();
return true;
}
return false;
}
3) Create custom onTouch listener where we will resize WebView and change Y-value of our bar
private OnTouchListener listener = new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
startEventY = event.getY();
heightChange = 0;
webViewOnTouchHeight = webView.getLayoutParams().height;
break;
case MotionEvent.ACTION_MOVE:
float delta = (event.getY()+heightChange)-startEventY;
boolean heigthChanged = resizeView(delta);
if (heigthChanged){
actionBar.setTranslationY(baseHeight - webView.getLayoutParams().height - barHeight);
}
}
return false;
}
};
There is now a really clean way to accomplish this without writing any Java code using the Design Support Library. See Dhir Pratap's answer below:
(I would have placed this as a comment but I don't have enough rep.)
How to Hide ActionBar/Toolbar While Scrolling Down in Webview
<android.support.design.widget.CoordinatorLayout 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.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.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.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:layout_gravity="fill_vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<WebView
android:id="#+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
try the following code, hope it works for you:
private void init(){
WebView web = new WebView(this);
final Context context = this;
web.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent event) {
// TODO Auto-generated method stub
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// show action bar
((Activity) context).getActionBar().show();
break;
case MotionEvent.ACTION_UP:
// hide action bar
((Activity) context).getActionBar().hide();
break;
default:
break;
}
return false;
}
});
}

SimpleOnGestureListener code not working in Android 2.2

I have some code that I wrote to implement a vertical swipe on a
Gallery widget. It works great in Android 1.5 and 1.6 but does not
work in Android 2.2 (I have yet to try it with 2.1).
public class SwipeUpDetector extends SimpleOnGestureListener
implements OnTouchListener
{
private GestureDetector m_detector;
public SwipeUpDetector()
{
m_detector = new GestureDetector(m_context, this);
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
if (Math.abs(e1.getX() - e2.getX()) < s_swipeMaxOffPath &&
e1.getY() - e2.getY() >= s_swipeMinDistance &&
Math.abs(velocityY) >= s_swipeMinVelocity)
{
int pos = m_gallery.pointToPosition((int)e1.getX(), (int)e2.getY());
startAnimation(pos);
return true;
}
return false;
}
#Override
public boolean onTouch(View v, MotionEvent event)
{
return m_detector == null ? false : m_detector.onTouchEvent(event);
}
}
And to be able to get my gallery to detect the onFling I have the
following:
m_gallery.setOnTouchListener(new SwipeUpDetector());
In Android 1.5 and 1.6 this works great. In Android 2.2 onFling() is
never called. In looking around on Google and StackOverflow I found
one possible solution was to implement onDown() and return true.
However, I am also listening to single clicks and have a context menu
listener set up on this gallery. When I implement onDown() and return
true I do indeed get the swipe to work. But when I do this the
context menu doesn't display on a long click and the single clicks
don't work either... Clicking on items in the gallery cause the
gallery to jump around and I don't get any feedback when I click on an
item in the gallery. It just immediately makes that item the selected
item and moves it to the center.
I looked at the API differences report between 1.6, 2.1, and 2.2 and
didn't see anthing of significance that could have caused this to
break...
What am I doing wrong?
EDIT:
It might also be helpful to know that the gallery is nested inside a couple layouts as follows (this isn't a complete layout... it is just intended to show the hierarchy of where this Gallery lives):
<ScrollView>
<LinearLayout>
<RelativeLayout> <!-- This relative layout is a custom one that I subclassed -->
<Gallery />
</RelativeLayout>
</LinearLayout>
</ScrollView>
EDIT #2:
Here are the requested layouts... There are two of them, for reusability purposes. Here is the first one, which is the main activity's layout:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myns="http://com.magouyaware/appswipe"
android:id="#+id/main_layout_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center_horizontal"
android:scrollbarAlwaysDrawVerticalTrack="false"
>
<LinearLayout
android:id="#+id/appdocks_layout_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginTop="10dp"
android:layout_gravity="center"
android:orientation="vertical"
android:gravity="center"
android:background="#null"
>
<com.magouyaware.appswipe.TitledGallery
android:id="#+id/running_gallery_layout_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
myns:gallery_title="#string/running_title"
/>
<com.magouyaware.appswipe.TitledGallery
android:id="#+id/recent_gallery_layout_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
myns:gallery_title="#string/recent_title"
/>
<com.magouyaware.appswipe.TitledGallery
android:id="#+id/favs_gallery_layout_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
myns:gallery_title="#string/favs_title"
/>
<com.magouyaware.appswipe.TitledGallery
android:id="#+id/service_gallery_layout_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
myns:gallery_title="#string/service_title"
/>
<com.magouyaware.appswipe.TitledGallery
android:id="#+id/process_gallery_layout_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
myns:gallery_title="#string/process_title"
/>
<include
android:id="#+id/indeterminate_progress_layout_id"
layout="#layout/indeterminate_progress_layout"
/>
</LinearLayout>
</ScrollView>
And here is the layout file for com.magouyaware.appswipe.TitledGallery... This is nothing more than a RelativeLayout subclass for the purpose of controlling several views as a single item in the code and for reusability:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/titled_gallery_main_layout_id"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
android:background="#null"
>
<LinearLayout
android:id="#+id/titled_gallery_expansion_layout_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:focusable="true"
android:clickable="true"
android:gravity="center_vertical"
>
<ImageView
android:id="#+id/titled_gallery_expansion_image_id"
android:layout_width="20dp"
android:layout_height="20dp"
android:duplicateParentState="true"
android:clickable="false"
/>
<TextView
style="#style/TitleText"
android:id="#+id/titled_gallery_title_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:paddingLeft="1sp"
android:paddingRight="10sp"
android:textColor="#drawable/titled_gallery_text_color_selector"
android:duplicateParentState="true"
android:clickable="false"
/>
</LinearLayout>
<Gallery
android:id="#+id/titled_gallery_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/titled_gallery_expansion_layout_id"
android:layout_alignWithParentIfMissing="true"
android:spacing="5sp"
android:clipChildren="false"
android:clipToPadding="false"
android:unselectedAlpha=".5"
android:focusable="false"
/>
<TextView
style="#style/SubTitleText"
android:id="#+id/titled_gallery_current_text_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="#id/titled_gallery_id"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_horizontal"
/>
</RelativeLayout>
I was able to receive single/double clicks and long click as well by implementing onSingleTapConfirmed, onDoubleTap and onLongPress in my implementation of SimpleOnGestureListener (while returning true from onDown).
Concerning why we should override onDown method. I think it is related to the issue #8233. It was reported one year ago against 2.1 version. Since only 10 people starred it so far I guess it would not be fixed in the near future.
UPDATE
It turned out that the issue was caused by the combination of ScrollView and Gallery and usage of OnTouchListener. Gallery itself implements OnGestureListener and encapsulates GestureDetector which is disabled when we set our OnTouchListener, resulting in a strange gallery behavior sometimes. On the other hand if we just subclass Gallery component and perform long-click/swipe detection in its onLongPress/onFling methods the parent ScrollView will intercept vertical move events preventing onFling call for such events. The solution is to override Gallery.dispatchTouchEvent and call requestDisallowInterceptTouchEvent(true) for gallery parent.
To summarize: if you want to detect swipes (long-, double-clicks etc.) for the Gallery (and possibly place it inside the ScrollView) use the custom component provided below instead of GestureDetector/OnTouchListener.
public class FlingGallery extends android.widget.Gallery implements OnDoubleTapListener {
private static final int SWIPE_MIN_VELOCITY = 30; // 30dp, set to the desired value
private static final int SWIPE_MIN_DISTANCE = 50; // 50dp, set to the desired value
private static final int SWIPE_MAX_OFF_PATH = 40; // 40dp, set to the desired value
private final float mSwipeMinDistance;
private final float mSwipeMaxOffPath;
private final float mSwipeMinVelocity;
public FlingGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
float density = context.getResources().getDisplayMetrics().density;
this.mSwipeMinDistance = density * SWIPE_MIN_DISTANCE;
this.mSwipeMaxOffPath = density * SWIPE_MAX_OFF_PATH;
this.mSwipeMinVelocity = density * SWIPE_MIN_VELOCITY;
}
public FlingGallery(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.galleryStyle);
}
public FlingGallery(Context context) {
this(context, null);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final ViewParent parent;
if (ev.getAction() == MotionEvent.ACTION_MOVE && (parent = getParent()) != null) {
parent.requestDisallowInterceptTouchEvent(true); // this will be passed up to the root view, i.e. ScrollView in our case
}
return super.dispatchTouchEvent(ev);
}
#Override
public boolean onDoubleTap(MotionEvent e) {
// Your double-tap handler...
return true;
}
#Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
#Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// Your single-tap handler...
return true;
}
#Override
public void onLongPress(MotionEvent event) {
// Your long-press handler...
super.onLongPress(event);
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e1 == null) {
return super.onFling(e1, e2, velocityX, velocityY);
}
float dx = e2.getX() - e1.getX();
float dy = e2.getY() - e1.getY();
if (abs(dx) < mSwipeMaxOffPath && abs(velocityY) > mSwipeMinVelocity && abs(dy) > mSwipeMinDistance) {
if (dy > 0) {
// Your from-top-to-bottom handler...
} else {
// Your from-bottom-to-top handler...
}
} else if (abs(dy) < mSwipeMaxOffPath && abs(velocityX) > mSwipeMinVelocity && abs(dx) > mSwipeMinDistance) {
if (dx > 0) {
// Your from-left-to-right handler...
} else {
// Your from-right-to-left handler...
}
}
return super.onFling(e1, e2, velocityX, velocityY);
}
}
If you do not handle the down you will not get any event (scroll, fling, up) linked to this down event. So you must return true.
I tried to understand why but I failed yet. Maybe since SimpleOnGestureListener returns false by default, and some new 2.2 optimizations in the outer Layout feels you do not want the event. You are not a valid target anymore for the chain of events.
To get your longPress working, can't you implement the onLongPress event in your detector and call the code that makes your menu appear?

scroll an image bigger than the screen and stop at its border on Android

I know how to display an image that is bigger than the screen. That's fairly simple and explained in details here, however, this method makes you able to scroll as far as you want, event if you have left the image and you just have black screen. I would like to know how we can make the scrolling stop when we reach the side of the picture...
Load your image into a WebView. Then you will get all the scroll behaviors you are looking for, and even the default zoom controls if you choose to turn them on...practically for free. Your only other option (to my knowledge) would be to used the 2D graphics APIs (Canvas, etc.) and create your own version of drawing tiles (like viewing a section of a map).
If your image is local, take a look at this example of reading local image data in from the SD Card. The cleaner approach to serving a local image in this case would be to create a ContentProvider and access the resource through a content:// URL in your WebView.
Example using the bundled image car.jpg in the assets directory of your project:
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView
android:id="#+id/web"
android:layout_width="150dip"
android:layout_height="150dip"
/>
</LinearLayout>
src/ImageViewer.java
public class ImageViewer extends Activity {
WebView webView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
webView = (WebView)findViewById(R.id.web);
webView.loadUrl("file:///android_asset/car.jpg");
}
}
For an image bundled with your project, that's the simplest method. This does not work with images in your resources directory (like res/drawable). That path is not worth the code required to complete it.
In your Activity.onCreate():
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(...);
I was not sure which layout you exactly mean so I am posting 2 versions:
Version 1 (Buton below the image):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<ScrollView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_weight="1"
android:fadingEdge="none" android:scrollbars="none">
<ImageView android:id="#+id/image" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:scaleType="center" />
</ScrollView>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="OK"
android:layout_gravity="center" />
</LinearLayout>
Version 2 (Button over the image - in z axis):
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent" android:fadingEdge="none"
android:scrollbars="none">
<ImageView android:id="#+id/image" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:scaleType="center" />
</ScrollView>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="OK"
android:layout_gravity="bottom|center_horizontal" />
</FrameLayout>
You can also try putting ScrollView inside a HorizontalScrollView.
Well I had same issue here is my solution:
Display display = getWindowManager().getDefaultDisplay();
screenSize = new Point();
display.getSize(screenSize);
Get screen size it will be required to set bottom and right boundaries
image.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float curX, curY;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mx = event.getX();
my = event.getY();
rect = image.getDrawable().getBounds();
break;
case MotionEvent.ACTION_MOVE:
curX = event.getX();
curY = event.getY();
image.scrollBy(getX((int) (mx - curX)), getY((int) (my - curY)));
mx = curX;
my = curY;
break;
}
return true;
}
});
and finally two methods to set new scroll coordinates
private int getX(int x){
if (image.getScrollX() + x < 0 ){ //left side
return 0;
} else if (image.getScrollX() + x >= (rect.right - screenSize.x)){ //right side
return 0;
} else {
return x;
}
}
private int getY(int y){
if (image.getScrollY() + y < 0 ){ //top side
return 0;
} else if (image.getScrollY() + y >= (rect.bottom - screenSize.y)){ //bottom side
return 0;
} else {
return y;
}
}
Works great API 16+, hope it will help

Categories

Resources