I am working on View Flipper in android . while compiling it does not showing any error . but as soon as application starts in my mobile Devices , it crashes. Since i'm very beginner in Android and does not have enough knowledge.
Report bug shows Null Pointer Exception to invoke viewFlipper.getDisplayChild()
Main java file codes are
package com.example.joshiyogesh.classapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.widget.ViewFlipper;
public class MainActivity extends Activity {
public ViewFlipper viewFlipper;
public float lastX;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewFlipper = (ViewFlipper)findViewById(R.id.view_flipper);
}
public boolean onTouchEvent(MotionEvent touchEvent){
switch (touchEvent.getAction()){
case MotionEvent.ACTION_DOWN:
{
lastX = touchEvent.getX();
break;
}
case MotionEvent.ACTION_UP:
{
float currentX = touchEvent.getX();
if (lastX<currentX){
if(viewFlipper.getDisplayedChild() == 0)
break;
viewFlipper.setInAnimation(this,R.anim.in_from_left);
viewFlipper.setOutAnimation(this,R.anim.out_from_right);
//show next Screen
viewFlipper.showNext();
}
if(lastX>currentX){
if(viewFlipper.getDisplayedChild()==1)
break;
viewFlipper.setInAnimation(this,R.anim.in_from_right);
viewFlipper.setOutAnimation(this,R.anim.out_from_left);
viewFlipper.showPrevious();
}
break;
}
}
return false;
}
}
ViewFlipper's file codes are
<?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:layout_height="match_parent">
<ViewFlipper
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/view_flipper"
android:layout_margin="6dip">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
>
<ImageView
android:layout_width="450dp"
android:layout_height="450dp"
android:layout_marginTop="15dp"
android:id="#+id/image_view1"
android:src="#drawable/images"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical"
>
<ImageView
android:layout_width="450dp"
android:layout_height="450dp"
android:layout_marginTop="15dp"
android:id="#+id/image_view2"
android:src="#drawable/large"/>
</LinearLayout>
</ViewFlipper>
</LinearLayout>
Any help would be Thankful.Thanks in advance.
update
Report Bug shown by devices
When using onTouchEvent the activity will send directly to it if no other functions invoke it first (ontouch listener onclick listener), you got two options
Option 1
Check if viewFlipper is null before using
Option 2
Use ontouchlistener in oncreate after findviewbyid to the flipper
viewFlipper.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP){
// Do what you want
return true;
}
return false;
}
});
Related
I am developing a piano app for android. I am trying to implement OnTouchListener for all the 8 buttons that I have in my activity. So, when the user drags or swipes his finger I want all the buttons to play the sound. I think the picture below explains it better.
See? When the user will place his hand on the first button and then drag till the last button, I want all the 8 buttons to play the song. But I am not able to achieve it. The below java code works only for the first button but the rest of the 7 buttons don't get pressed.
Here it is:
#Override
public boolean onTouch(View v, MotionEvent event) {
switch(v.getID())
{
case(R.id.btn1):
//play button 1 sound
break;
case(R.id.btn2):
//play button 2 sound
break;
case(R.id.btn3):
//play button 3 sound
break;
case(R.id.btn4):
//play button 4 sound
break;
case(R.id.btn5):
//play button 1 sound
break;
case(R.id.btn6):
//play button 6 sound
break;
case(R.id.btn7):
//play button 7 sound
break;
case(R.id.btn8):
//play button 8 sound
break;
}
return true;
}
I have already seen this question and this as well but couldn't find an answer there.
Please help me out. Thank you for you time!
You should implement onTouchListner on the layout which contains the piano buttons
The idea is to get all piano buttons positions on the screen (x , y) after render them.
then get touch position by using getX() and getY() methods.
At this point you can handle it by checking if the touch x and y is between the view start and
end x and y, then play the sound of the view.
At this example i'am using soundpool and pitch to play different sounds (i know that it's not the perfect way), and i'm also working on x factor only because i'm using piano white keys only.
import android.app.Activity;
import android.media.*;
import android.os.Bundle;
import android.view.*;
import android.widget.*;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity
{
//The layout that holds the piano keys.
LinearLayout pianoKeysContainer;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pianoKeysContainer = (LinearLayout) findViewById(R.id.key_container);
pianoKeysContainer.setOnTouchListener(onYourViewTouchListener);
}
//Here we load the view positions after render it and fill the array with the positions
private List<Integer> positionsLeft_whiteKeys = new ArrayList<Integer>();
private List<Integer> positionsRight_whiteKeys = new ArrayList<Integer>();
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
for (int i = 0; i < pianoKeysContainer.getChildCount(); i++)
{
//positionsLeft_whiteKeys holds the start x of each view.
positionsLeft_whiteKeys.add(pianoKeysContainer.getChildAt(i).getLeft());
//positionsRight_whiteKeys holds the end x of each view.
positionsRight_whiteKeys.add(pianoKeysContainer.getChildAt(i).getRight());
}
}
public View.OnTouchListener onYourViewTouchListener = new View.OnTouchListener()
{
float positionX;
FrameLayout pianoKey;
FrameLayout lastPlayedKey;
ArrayList<FrameLayout> pressedKeys = new ArrayList<FrameLayout>();
#Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
positionX = motionEvent.getX();
float pitch;
//Looping on the child of the layout which contains the piano keys
for (int x = 0; x < ((LinearLayout) view).getChildCount(); x++)
{
// Calculating the pitch to get good chords
pitch = (float) Math.pow(Math.pow(2.0, 1 / 12.0), (float) x);
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (positionsLeft_whiteKeys.size() >= 0 && positionsRight_whiteKeys.size() >= 0)
{
if (positionX > positionsLeft_whiteKeys.get(x) && positionX < positionsRight_whiteKeys.get(x))
{
pianoKey = (FrameLayout) ((LinearLayout) view).getChildAt(x);
if (pianoKey != null)
{
pianoKey.setBackgroundResource(R.drawable.piano_key_pressed);
pressedKeys.add(pianoKey);
}
if (lastPlayedKey != pianoKey)
playKey(pitch);
lastPlayedKey = pianoKey;
break;
}
if (lastPlayedKey != null)
{
pianoKey.setBackgroundResource(R.drawable.piano_key);
lastPlayedKey.setBackgroundResource(R.drawable.piano_key);
}
}
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
{
lastPlayedKey = null;
for (FrameLayout pressedKey : pressedKeys)
{
pressedKey.setBackgroundResource(R.drawable.piano_key);
}
}
return false;
}
};
//This is sound play method
SoundPool sp = new SoundPool(1, AudioManager.STREAM_MUSIC, 1);
public void playKey(final float pitch)
{
//here you should store your piano sound at res/raw then load it
sp.load(this, R.raw.piano, 1);
sp.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener()
{
#Override
public void onLoadComplete(SoundPool soundPool, int i, int i2)
{
soundPool.play(i, 0.99f, 0.99f, 1, 0, pitch);
}
});
}
}
And this is the xml file (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="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:id="#+id/key_container">
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"
/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
<FrameLayout
android:layout_height="match_parent"
android:layout_marginRight="2dp"
android:layout_width="48dp"
android:background="#drawable/piano_key"/>
</LinearLayout>
</LinearLayout>
Note: the only thing you should do to complete the example is to put
you piano key image (pressed and not pressed) and put the piano sound
at res/raw
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>
I can't get onTouch event triggered on a container when clicking on its ScrollView child.
I'm using API 12 on a Galaxy tab 10.1.
Anybody can help?
Thanks
Activity
public class TestActivity extends Activity{
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.dude);
LinearLayout mylayout = (LinearLayout) findViewById(R.id.mylayout);
mylayout.setOnTouchListener(new OnTouchListener () {
public boolean onTouch(View view, MotionEvent event) {
// Only called when touched outside the ScrollView
if (event.getAction() == android.view.MotionEvent.ACTION_DOWN) {
/* do stuff */
} else if (event.getAction() == android.view.MotionEvent.ACTION_UP) {
/* do stuff */
}
return true;
}
});
}
}
Layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mylayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical" >
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="center"
android:text="Touch here trigger parent's onTouch"
android:textColor="#000000"
android:textSize="40sp" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="match_parent"
android:layout_height="1000dp"
android:background="#b00000"
android:gravity="center"
android:text="Touch here DOES NOT trigger parent's onTouch"
android:textColor="#000000"
android:textSize="40sp" />
</RelativeLayout>
</ScrollView>
</LinearLayout>
mylayout.setOnTouchListener(new OnTouchListener () {
public boolean onTouch(View view, MotionEvent event) {
// Only called when touched outside the ScrollView
if (event.getAction() == android.view.MotionEvent.ACTION_DOWN) {
/* do stuff */
return true;
} else if (event.getAction() == android.view.MotionEvent.ACTION_UP) {
/* do stuff */
return true;
}
return false;
}
});
this should work... but you no longer have auto-scroll when you fling it hard... it'll be a sticky scroll moving only as much as you drag.
Did u try to create ONE OnClickListener and add it to all childs?
Maybe this could solve your
As the ScrollView makes it childs scrollable it wouldn't have an own area to click in.
(Correct me if I'm wrong ^^)
You probably need this code
#Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return false;
}
I have a dialog to choose files from. This dialog contains a listview to show directories and files and has an onItemClickListener for navigation purposes.
How can I react to fling events to go up in the directory structure? I tried setting an OnTouchListener on the root RelativeLayout to dispatches touch events to my GestureListener:
final GestureDetector detector = new GestureDetector(new MyGestureDetector(tvCurrentPath));
dialog.findViewById(R.id.rlFilelist).setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View view, MotionEvent e) {
detector.onTouchEvent(e);
return false;
}
});
The events get registered in onTouch(), but the onFling() method is never called in the MyGestureDetector. If, however, I attach the OnTouchListener to the listview, it works as expected. The problem with this approach is that the listview is not always filled extensively with data and when it is empty or when clicking below items, no onTouch() events are triggered.
Dialog layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/rlFilelist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:focusable="true" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/llButtons" >
<TextView
android:id="#+id/tvCurrentPath"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip" >
</TextView>
<ListView
android:id="#+id/lvFileListing"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="#id/llButtons"
android:layout_below="#id/tvCurrentPath" >
</ListView>
</RelativeLayout>
<RelativeLayout
android:id="#+id/llButtons"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="5dip"
android:layout_marginTop="5dip" >
<Button
android:id="#+id/btAddDirectory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginRight="10px"
android:text="#string/host_tv_dg_add_directory" />
<Button
android:id="#+id/btUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10px"
android:layout_toRightOf="#id/btAddDirectory"
android:text="#string/host_tv_dg_navigate_up" />
<Button
android:id="#+id/btClose"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/btUp"
android:text="#string/_tv_close" />
</RelativeLayout>
</RelativeLayout>
Screenshot for dialog with not completely filled lisview:
http://imageshack.us/photo/my-images/802/dialog.png/
How can I make the onFling() events trigger on the whole dialog or on the "whole" listview even when it's not completely filled with items?
Thank you!
You should create a class which extends the dialog class and then you can create a gesture detector and attach to the ontouchevent of the class.
Here is a code example:
public class GestureDialog extends Dialog {
public GestureDialog (Context context, int theme) {
super(context, theme);
gestDetec = new MyGestureDetector(); //inital setup
gestureDetector = new GestureDetector(gestDetec);
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
return false;
}
};
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event))
return true;
else
return false;
}
class MyGestureDetector extends SimpleOnGestureListener {
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
System.out.println( "Help im being touched!" );
return false;
}
}
}
You can Take one activity and set it's theme in manifest to dialog.
Then implements onTouchListener to that activty
and write one onTouch() event in that Activity.
Now you got Touch event for entire dialog :)
How does one drag an image from one layout to another layout. I am attaching what i have done so far. I have two layouts in a single view. I can move the image on its initial layout. But the problem is i cant move the image to a different layout. Please help me find the solution to this problem.
<?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"> <LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<ImageView
android:id="#+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/icon"
android:scaleType="matrix"
android:layout_weight="1">
</ImageView>
<ImageView
android:id="#+id/imageView2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#drawable/icon"
android:scaleType="matrix"
android:layout_weight="1"
android:background="#00aa00"
>
</ImageView>
</LinearLayout>
</LinearLayout>
and main file is
package com.example.multitouch;
import android.app.Activity;
import android.graphics.Matrix;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
public class multitouch extends Activity implements OnTouchListener{
/** Called when the activity is first created. */
Matrix matrix = new Matrix() ;
Matrix eventmatrix = new Matrix();
static float centerX,centerY;
final static int NONE = 0;
final static int DRAG = 1;
int touchState=NONE;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView view = (ImageView) findViewById(R.id.imageView);
view.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
ImageView view = (ImageView) v;
final int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
touchState= DRAG;
centerX= event.getX();
centerY = event.getY();
eventmatrix.set(matrix);
break;
case MotionEvent.ACTION_MOVE:
if (touchState == DRAG) {
matrix.set(eventmatrix);
matrix.setTranslate(event.getX()-centerX,event.getY()-centerY);
}
view.setImageMatrix(matrix);
//view.setImageMatrix(eventmatrix);
break;
case MotionEvent.ACTION_UP:
//touchState=NONE;
break;
}
return true;
}
}
Please give me a reply
It can get really complicated, but check this out:
http://blahti.wordpress.com/2011/02/10/moving-views-part-3/
How can you move it to another layout if it's not its child? I'd try to wrap your root layout into RelativeLayout and place the image there, so you could move it wherever you want.
Something like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<ImageView/>
<LinearLayout>
<LinearLayout/>
</LinearLayout>
</RelativeLayout>