i found this code in a post that used on touch listener for linear layout.
in linear layout there is some child layout and each one play same sound but with pitch . now how can i use each child to play a different sound .
the other word how can i access to each child?
public class MainActivity extends Activity {
LinearLayout pianoKeysContainer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
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.dinger14);
pressedKeys.add(pianoKey);
}
if (lastPlayedKey != pianoKey)
playKey(pitch);
lastPlayedKey = pianoKey;
break;
}
if (lastPlayedKey != null)
{
pianoKey.setBackgroundResource(R.drawable.dinger14);
lastPlayedKey.setBackgroundResource(R.drawable.dinger14);
}
}
}
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
{
lastPlayedKey = null;
for (FrameLayout pressedKey : pressedKeys)
{
pressedKey.setBackgroundResource(R.drawable.dinger14);
}
}
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.chitare3, 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);
}
});
}
}
If you have no need of parent on touch event then directly apply this same event on each child...
pianoKeysContainer1 = (LinearLayout) findViewById(R.id.key_child1);
pianoKeysContainer2 = (LinearLayout) findViewById(R.id.key_child2);
pianoKeysContainer1.setOnTouchListener(onYourViewTouchListener);
pianoKeysContainer2.setOnTouchListener(onYourViewTouchListener);
You can apply onYourViewTouchListener onTouchListener on each child as shown above.
Then in View.onTouchListener check which child listener is called by checking view id.
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)
{
// Check **view id** here and apply required action based on this view id.
.............
.............
Related
Here is the problem I am facing. On a empty relative layout, when touched textview is instantiated at the touched x y position. I got this far correct, but the problem is that when I touch on the empty space near already instantiated view, previous view and currently placed views are overlapped. I tried by the getting the child views of the layout and checking the current view and already placed view using rect data that if they intersect. How to solve this problem?
Here is the code:
public class MainActivity extends AppCompatActivity
{
private int id = 0;
private RelativeLayout root;
private RelativeLayout.LayoutParams params;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_designer);
root = (RelativeLayout) findViewById(R.id.rootlayout);
root.setOnTouchListener(new View.OnTouchListener()
{
#Override
public boolean onTouch(View v, MotionEvent event)
{
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
instantiateView(v, event);
break;
}
return true;
}
});
}
private void instantiateView(View v, MotionEvent event)
{
int x = (int) event.getX();
int y = (int) event.getY();
TextView bt = new TextView(DesignerActivity.this);
bt.setText("1");
bt.setId(++id);
bt.setBackgroundColor(Color.BLACK);
bt.setTextColor(Color.WHITE);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
showDialog();
}
});
params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(x, y, 0, 0);
bt.setLayoutParams(params);
//((ViewGroup) v).addView(bt);
if(root.getChildCount() <= 0)
{
((ViewGroup) v).addView(bt);
}
else
{
for (int i = 0; i < root.getChildCount(); i++)
{
if (!checkCollision(bt, root.getChildAt(i)))
{
if(bt != root.getChildAt(i))
{
((ViewGroup) v).addView(bt);
}
}
}
}
}
private void showDialog()
{
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.dialog_layout);
Button editBtn = (Button) dialog.findViewById(R.id.button1);
Button deleteBtn = (Button) dialog.findViewById(R.id.button2);
editBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
deleteBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
dialog.dismiss();
}
});
dialog.show();
}
private boolean checkCollision(View v1, View v2)
{
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
}
You are using Relative Layout that's why your Textviews are overlapping.
If you don't want the overlapping and want to place it next or somewhere else to the overlapped view , it is your decision. Just check if they intersect and take appropriate decision based on your requirement.
Below line is the problem in your code.
Rect r1 = new Rect(v1.getLeft(), v1.getTop(), v1.getRight(), v1.getBottom());
You set the params' Margin does not mean that you will get desired left,top,right, bottom values.You will get these values right after the inflation of your view hierarchy.
You can use this function:
private boolean checkCollision(View v1, View v2)
{
int leftMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).leftMargin;
int topMargin = ((RelativeLayout.LayoutParams) v1.getLayoutParams()).topMargin;
Rect r1 = new Rect(root.getPaddingLeft() + leftMargin, root.getPaddingTop() + topMargin,
root.getPaddingLeft() + leftMargin + v2.getWidth(), root.getPaddingTop() + topMargin + v2.getHeight());
Rect r2 = new Rect(v2.getLeft(), v2.getTop(), v2.getRight(), v2.getBottom());
return r1.intersect(r2);
}
After that use
params.addRule(); according to your requirement where you want to place your overlapping view.
m trying to build android new inbox style listview with swipe left and right as shown in this image , i have tried 47deg swipelistview but its not that stable , is there any other library available?!
Tried so far with 47 deg
public class MainActivity extends Activity {
Listview pullToRefreshListView;
SwipeListView swipelistview;
ItemAdapter adapter;
List<ItemRow> itemData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pullToRefreshListView = (ListView) findViewById(R.id.example_swipe_lv_list);
swipelistview = pullToRefreshListView.getRefreshableView();
itemData = new ArrayList<ItemRow>();
adapter = new ItemAdapter(this, R.layout.custom_row, itemData);
swipelistview.setSwipeListViewListener(new BaseSwipeListViewListener() {
#Override
public void onOpened(int position, boolean toRight) {
if (toRight) {
adapter.remove(position);
Toast.makeText(MainActivity.this, "Open to dismiss",
Toast.LENGTH_SHORT).show();
} // swipelistview.dismiss(position);
else {
Toast.makeText(MainActivity.this, "Open to edit",
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onClosed(int position, boolean fromRight) {
}
#Override
public void onListChanged() {
}
#Override
public void onMove(int position, float x) {
}
#Override
public void onStartOpen(int position, int action, boolean right) {
if (right) {
// adapter.onRight();
swipelistview.getChildAt(position).findViewById(R.id.back)
.setBackgroundColor(Color.GREEN);
swipelistview.getChildAt(position)
.findViewById(R.id.imageViewLeft)
.setVisibility(View.VISIBLE);
swipelistview.getChildAt(position)
.findViewById(R.id.imageViewRight)
.setVisibility(View.GONE);
} else {
// adapter.onLeft();
swipelistview.getChildAt(position).findViewById(R.id.back)
.setBackgroundColor(Color.RED);
swipelistview.getChildAt(position)
.findViewById(R.id.imageViewLeft)
.setVisibility(View.GONE);
swipelistview.getChildAt(position)
.findViewById(R.id.imageViewRight)
.setVisibility(View.VISIBLE);
}
}
#Override
public void onStartClose(int position, boolean right) {
Log.d("swipe", String.format("onStartClose %d", position));
}
#Override
public void onClickFrontView(int position) {
Log.d("swipe", String.format("onClickFrontView %d", position));
// swipelistview.openAnimate(position); //when you touch front
// view it will open
}
#Override
public void onClickBackView(int position) {
Log.d("swipe", String.format("onClickBackView %d", position));
// swipelistview.closeAnimate(position);//when you touch back
// view it will close
}
#Override
public void onDismiss(int[] reverseSortedPositions) {
}
});
// These are the swipe listview settings. you can change these
// setting as your requirement
swipelistview.setSwipeMode(SwipeListView.SWIPE_MODE_BOTH); // there are
// five
// swiping
// modes
swipelistview.setSwipeActionRight(SwipeListView.SWIPE_ACTION_REVEAL); // there
// are
// four
// swipe
// actions
swipelistview.setSwipeActionLeft(SwipeListView.SWIPE_ACTION_REVEAL);
swipelistview.setOffsetRight(convertDpToPixel(0f)); // left side
// offset
swipelistview.setOffsetLeft(convertDpToPixel(0f)); // right side
// offset
swipelistview.setAnimationTime(60); // Animation time
swipelistview.setSwipeOpenOnLongPress(false); // enable or disable
// SwipeOpenOnLongPress
swipelistview.setSwipeCloseAllItemsWhenMoveList(true);
swipelistview.setAdapter(adapter);
for (int i = 0; i < 10; i++) {
itemData.add(new ItemRow("Swipe Item" + i, getResources()
.getDrawable(R.drawable.ic_launcher)));
}
adapter.notifyDataSetChanged();
}
public int convertDpToPixel(float dp) {
DisplayMetrics metrics = getResources().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return (int) px;
}
}
Adapter class
public class ItemAdapter extends ArrayAdapter<ItemRow> {
List<ItemRow> data;
Context context;
int layoutResID;
public ItemAdapter(Context context, int layoutResourceId, List<ItemRow> data) {
super(context, layoutResourceId, data);
this.data = data;
this.context = context;
this.layoutResID = layoutResourceId;
// TODO Auto-generated constructor stub
}
NewsHolder holder = null;
View row = null;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
row = convertView;
holder = null;
if (row == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(layoutResID, parent, false);
holder = new NewsHolder();
holder.itemName = (TextView) row
.findViewById(R.id.example_itemname);
holder.icon = (ImageView) row.findViewById(R.id.example_image);
holder.imageViewRight = (ImageView) row
.findViewById(R.id.imageViewRight);
holder.imageViewLeft = (ImageView) row
.findViewById(R.id.imageViewLeft);
row.setTag(holder);
} else {
holder = (NewsHolder) row.getTag();
}
ItemRow itemdata = data.get(position);
holder.itemName.setText(itemdata.getItemName());
holder.icon.setImageDrawable(itemdata.getIcon());
return row;
}
public void remove(int pos){
data.remove(pos);
}
public void onLeft() {
holder.imageViewLeft.setVisibility(View.VISIBLE);
holder.imageViewRight.setVisibility(View.GONE);
}
public void onRight() {
holder.imageViewRight.setVisibility(View.VISIBLE);
holder.imageViewLeft.setVisibility(View.GONE);
}
static class NewsHolder {
TextView itemName;
ImageView icon;
ImageView imageViewLeft, imageViewRight;
RelativeLayout mRelativeLayout;
}
Instead of using a custom ListView you can simply support "swipe" gesture on list items onTouch, like the following:
private static final int DEFAULT_THRESHOLD = 128;
row.setOnTouchListener(new View.OnTouchListener() {
int initialX = 0;
final float slop = ViewConfiguration.get(context).getScaledTouchSlop();
public boolean onTouch(final View view, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
initialX = (int) event.getX();
view.setPadding(0, 0, 0, 0);
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int currentX = (int) event.getX();
int offset = currentX - initialX;
if (Math.abs(offset) > slop) {
view.setPadding(offset, 0, 0, 0);
if (offset > DEFAULT_THRESHOLD) {
// TODO :: Do Right to Left action! And do nothing on action_up.
} else if (offset < -DEFAULT_THRESHOLD) {
// TODO :: Do Left to Right action! And do nothing on action_up.
}
}
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
// Animate back if no action was performed.
ValueAnimator animator = ValueAnimator.ofInt(view.getPaddingLeft(), 0);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
view.setPadding((Integer) valueAnimator.getAnimatedValue(), 0, 0, 0);
}
});
animator.setDuration(150);
animator.start();
}
};
I also use reverse animation if no action was performed.
This solution is lightweight so you should not experience any lags.
Check out: SwipeActionAdapter
It's a great library that does exactly what you're asking for. It allows Swipe in both directions with an underlying Layout or Color. It's easy to implement and looks nice!
Updated Answer
As I mentioned previously, I took the same approach and it seems to work as expected. I have added 3 layers to a RelativeLayout. Top layer is what you want to show. Second layer is a plain background with delete icon at the left. Third layer is another plain background with share icon at the right. I implemented a swipe detector class which extends View.OnTouchListener.
public class SwipeDetector implements View.OnTouchListener {
private static final int MIN_DISTANCE = 300;
private static final int MIN_LOCK_DISTANCE = 30; // disallow motion intercept
private boolean motionInterceptDisallowed = false;
private float downX, upX;
private ObjectHolder holder;
private int position;
public SwipeDetector(ObjectHolder h, int pos) {
holder = h;
position = pos;
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
return true; // allow other events like Click to be processed
}
case MotionEvent.ACTION_MOVE: {
upX = event.getX();
float deltaX = downX - upX;
if (Math.abs(deltaX) > MIN_LOCK_DISTANCE && listView != null && !motionInterceptDisallowed) {
listView.requestDisallowInterceptTouchEvent(true);
motionInterceptDisallowed = true;
}
if (deltaX > 0) {
holder.deleteView.setVisibility(View.GONE);
} else {
// if first swiped left and then swiped right
holder.deleteView.setVisibility(View.VISIBLE);
}
swipe(-(int) deltaX);
return true;
}
case MotionEvent.ACTION_UP:
upX = event.getX();
float deltaX = upX - downX;
if (Math.abs(deltaX) > MIN_DISTANCE) {
// left or right
swipeRemove();
} else {
swipe(0);
}
if (listView != null) {
listView.requestDisallowInterceptTouchEvent(false);
motionInterceptDisallowed = false;
}
holder.deleteView.setVisibility(View.VISIBLE);
return true;
case MotionEvent.ACTION_CANCEL:
holder.deleteView.setVisibility(View.VISIBLE);
return false;
}
return true;
}
private void swipe(int distance) {
View animationView = holder.mainView;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) animationView.getLayoutParams();
params.rightMargin = -distance;
params.leftMargin = distance;
animationView.setLayoutParams(params);
}
private void swipeRemove() {
remove(getItem(position));
notifyDataSetChanged();
}
}
public static class ObjectHolder {
public LinearLayout mainView;
public RelativeLayout deleteView;
public RelativeLayout shareView;
/* other views here */
}
I have also added requestDisallowInterceptTouchEvent so that ListView (which is parent) doesn't intercept the touch event when there's some amount of vertical scrolling involved.
I have written a blogpost about it which you can find it here. I have also added a Youtube video for demo.
Old Answer
I implemented one of these myself, but it's a bit different. I use just touch instead of swiping. Touch to open, touch to close. Here's youtube demo.
I created custom ArrayAdapter. To set the layout, I created a custom layout like this.
<RelativeLayout>
<RelativeLayout>
<Stuff that you want at the back of your list/>
</RelativeLayout>
<RelativeLayout>
<Stuff that you want at the front of your list/>
</RelativeLayout>
</RelativeLayout>
Using RelativeLayout, I am putting the top view over the bottom view. Both have same sizes. You can use different layouts for inner layouts.
In Custom ArrayAdapter,
#Override
public view getView(int position, View convertView, ViewGroup parent) {
// get holder and entry
// set each element based on entry preferences
holder.topView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (entry.isSwiped()) {
swipeWithAnimationValue(holder.topView, 1);
entry.setSwiped(false);
} else {
closeOtherSwipes(entry); // if you want to keep only one entry open at a time
swipeWithAnimationValue(holder.topView, 0);
entry.setSwiped(true);
}
}
});
}
Normal Animation would not work as it just shifts the view, but it's still there so if you try to click, the click still occurs on the top view. Hence I have used valueAnimator and actually shifted those lists.
public void swipeWithAnimationValue(final View view, final int direction) {
final int width = view.getWidth();
Log.i(TAG, "view width = " + String.valueOf(width));
ValueAnimator animationSwipe;
int duration = 300;
if (direction == 0) {
animationSwipe = ValueAnimator.ofInt(0, view.getWidth() - 200);
} else {
animationSwipe = ValueAnimator.ofInt(view.getWidth() - 200, 0);
}
animationSwipe.setDuration(duration);
AnimatorUpdateListener maringUpdater = new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
params.rightMargin = -(Integer)animation.getAnimatedValue();
params.leftMargin = (Integer)animation.getAnimatedValue();
view.setLayoutParams(params);
}
};
animationSwipe.addUpdateListener(maringUpdater);
animationSwipe.setRepeatCount(0);
animationSwipe.start();
}
I am developing one app where I am dragging around my ImageView in Activity.
I have configured Facebook Rebound library for spring animation which is originally used in Facebook Messenger's chat heads animations. I want to add this kind of animations to my ImageView when I drag it.
VIDEO
So far I am able to get spring animation when I touch ImageView (implemented spring on rootview), this is my code. How can I implement that natural type of dragging effect to my ImageView.
public class MainTry extends Activity {
int windowwidth;
int windowheight;
private LayoutParams layoutParams;
private final BaseSpringSystem mSpringSystem = SpringSystem.create();
private FrameLayout mRootView;
private Spring spring;
private View mImageView;
private VelocityTracker velocity = null;
private float dx;
private float dy;
private View rootView;
private ImageView img;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
// Create a system to run the physics loop for a set of springs.
SpringSystem springSystem = SpringSystem.create();
// Add a spring to the system.
spring = springSystem.createSpring();
rootView = getWindow().getDecorView()
.findViewById(android.R.id.content);
windowwidth = getWindowManager().getDefaultDisplay().getWidth();
windowheight = getWindowManager().getDefaultDisplay().getHeight();
img = (ImageView) findViewById(R.id.imageView2);
rootView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// spring.setEndValue(1);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// spring.setEndValue(0);
break;
}
return true;
}
});
// Add a listener to observe the motion of the spring.
spring.addListener(new SimpleSpringListener() {
#Override
public void onSpringUpdate(Spring spring) {
// You can observe the updates in the spring
// state by asking its current value in onSpringUpdate.
float value = (float) spring.getCurrentValue();
float scale = .5f - (value * 0.1f);
img.setScaleX(scale);
img.setScaleY(scale);
}
});
// spring.setEndValue(1);
img.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
LayoutParams layoutParams = (LayoutParams) img
.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
dx = event.getRawX() - 10;
dy = event.getRawY() - 10;
if (velocity == null) {
// Retrieve a new VelocityTracker object to watch the
// velocity of a motion.
velocity = VelocityTracker.obtain();
} else {
// Reset the velocity tracker back to its initial state.
velocity.clear();
}
break;
case MotionEvent.ACTION_MOVE:
dx = event.getRawX() - 10;
dy = event.getRawY() - 10;
velocity.addMovement(event);
spring.setVelocity(velocity.getYVelocity());
spring.setCurrentValue(dy);
spring.setEndValue(dy);
layoutParams.leftMargin = (int) dx - 10;
layoutParams.topMargin = (int) dy - 10;
img.setLayoutParams(layoutParams);
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
velocity.addMovement(event);
spring.setVelocity(velocity.getYVelocity());
spring.setCurrentValue(event.getRawY() - 10);
spring.setEndValue(0);
break;
default:
break;
}
return true;
}
});
}
#Override
public void onResume() {
super.onResume();
}
#Override
public void onPause() {
super.onPause();
}
}
what about this:
class V extends View implements SpringListener {
private static final int NUM_ELEMS = 4;
private Spring[] mXSprings = new Spring[NUM_ELEMS];
private Spring[] mYSprings = new Spring[NUM_ELEMS];
private Paint mPaint = new Paint();
private Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
public V(Context context) {
super(context);
SpringSystem ss = SpringSystem.create();
Spring s;
for (int i = 0; i < NUM_ELEMS; i++) {
s = ss.createSpring();
s.setSpringConfig(new MySpringConfig(200, i == 0? 8 : 15 + i * 2, i, true));
s.addListener(this);
mXSprings[i] = s;
s = ss.createSpring();
s.setSpringConfig(new MySpringConfig(200, i == 0? 8 : 15 + i * 2, i, false));
s.addListener(this);
mYSprings[i] = s;
}
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mXSprings[0].setCurrentValue(w / 2);
mYSprings[0].setCurrentValue(0);
mXSprings[0].setEndValue(w / 2);
mYSprings[0].setEndValue(h / 2);
}
#Override
public void onSpringActivate(Spring s) {
}
#Override
public void onSpringAtRest(Spring s) {
}
#Override
public void onSpringEndStateChange(Spring s) {
}
#Override
public void onSpringUpdate(Spring s) {
MySpringConfig cfg = (MySpringConfig) s.getSpringConfig();
if (cfg.index < NUM_ELEMS - 1) {
Spring[] springs = cfg.horizontal? mXSprings : mYSprings;
springs[cfg.index + 1].setEndValue(s.getCurrentValue());
}
if (cfg.index == 0) {
invalidate();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mXSprings[0].setEndValue(event.getX());
mYSprings[0].setEndValue(event.getY());
return true;
}
#Override
protected void onDraw(Canvas canvas) {
for (int i = NUM_ELEMS - 1; i >= 0; i--) {
mPaint.setAlpha(i == 0? 255 : 192 - i * 128 / NUM_ELEMS);
canvas.drawBitmap(mBitmap,
(float) mXSprings[i].getCurrentValue() - mBitmap.getWidth() / 2,
(float) mYSprings[i].getCurrentValue() - mBitmap.getHeight() / 2,
mPaint);
}
}
class MySpringConfig extends SpringConfig {
int index;
boolean horizontal;
public MySpringConfig(double tension, double friction, int index, boolean horizontal) {
super(tension, friction);
this.index = index;
this.horizontal = horizontal;
}
}
}
i have used above V class directly in Window-manager and it's work perfectly and chatHead move like facebook messenger.
public class ChatHeadService extends Service
{
private LayoutInflater inflater;
private WindowManager windowManager;
private Point szWindow = new Point();
#Override
public void onCreate()
{
super.onCreate();
Log.v(Utils.LogTag, "Start Service");
}
private
void handleStart(){
windowManager = (WindowManager)getSystemService(WINDOW_SERVICE);
inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
if (Build . VERSION . SDK_INT >= Build . VERSION_CODES . HONEYCOMB) {
windowManager . getDefaultDisplay() . getSize(szWindow);
} else {
int w = windowManager . getDefaultDisplay() . getWidth();
int h = windowManager . getDefaultDisplay() . getHeight();
szWindow . set(w, h);
}
WindowManager . LayoutParams params = new WindowManager . LayoutParams(
WindowManager . LayoutParams . WRAP_CONTENT,
WindowManager . LayoutParams . WRAP_CONTENT,
WindowManager . LayoutParams . TYPE_PHONE,
WindowManager . LayoutParams . FLAG_NOT_FOCUSABLE |
WindowManager . LayoutParams . FLAG_WATCH_OUTSIDE_TOUCH |
WindowManager . LayoutParams . FLAG_LAYOUT_NO_LIMITS,
PixelFormat . TRANSLUCENT
);
params . gravity = Gravity . TOP | Gravity . LEFT;
params . x = 50;
params . y = 100;
V vImg = new V(this);
windowManager . addView(vImg, params);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
if (startId == Service . START_STICKY) {
handleStart();
}
}
return super . onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy(){
super . onDestroy();
if (windowManager != null) {
// windowManager.removeView(chatHeadView);
}
}
}
I have a 5x5 grid (I ve drawn a matrix in canvas). I ve arranged the textviews in the the grid
in the order of a array..ie (5X5 ) array. The thing is I want to change the values on of the text view when I swipe horizontally or vertically.
Say suppose I am using a touch movement on the screen continuously from [4][0] to [4][2] I want to modify the values of the textviews in those places.
Any ideas?
This piece of code might help you:
public class MyClass extends Activity implements OnGestureListener{
ArrayList<TextView> tvs = new ArrayList<TextView>();
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.mygrid);
}
public void onResume() {
super.onResume();
GestureOverlayView gd = (GestureOverlayView)findViewById(R.id.gd);
LinearLayout g = (LinearLayout)findViewById(R.id.mygrid);
gd.addOnGestureListener(this);
g.setOrientation(LinearLayout.VERTICAL);
for (int i = 0; i < 5; i++) {
LinearLayout row = new LinearLayout(this);
g.addView(row);
row.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams rowlp = (LayoutParams) row.getLayoutParams();
rowlp.width = LayoutParams.MATCH_PARENT;
rowlp.weight = 1;
rowlp.height = LayoutParams.WRAP_CONTENT;
row.setLayoutParams(rowlp);
for (int j = 0; j < 5; j++) {
TextView tv = new TextView(this);
row.addView(tv);
LinearLayout.LayoutParams lp = (LayoutParams) tv.getLayoutParams();
lp.height = LayoutParams.MATCH_PARENT;
lp.width = 0;
lp.weight = 1;
tv.setLayoutParams(lp);
tv.setText(String.valueOf(i * 5 + j));
tv.setTag(String.valueOf(i * 5 + j));
tv.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
tvs.add(tv);
if ((i * 5 + j) % 2 == 0)
tv.setBackgroundColor(0xff888888);
}
}
}
private boolean isPointInsideView(float x, float y, View view){
int location[] = new int[2];
view.getLocationOnScreen(location);
int viewX = location[0];
int viewY = location[1];
//point is inside view bounds
if(( x > viewX && x < (viewX + view.getWidth())) &&
( y > viewY && y < (viewY + view.getHeight()))){
return true;
} else {
return false;
}
}
#Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
float x = event.getRawX();
float y = event.getRawY();
for (TextView v : tvs) {
if (isPointInsideView(x, y, v)) {
v.setText("HERE");
}
}
}
#Override
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
}
#Override
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
}
#Override
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<android.gesture.GestureOverlayView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gd"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:id="#+id/mygrid"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.gesture.GestureOverlayView>
Hope it helps.
Edit2: replace the methods above with these for highly increased performance:
private TextView getAbove(float x, float y) {
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
if (isPointInsideView(x, y, tvs[i][j]))
return tvs[i][j];
return null;
}
#Override
public void onGesture(GestureOverlayView overlay, MotionEvent event) {
float x = event.getRawX();
float y = event.getRawY();
if (last == null || !isPointInsideView(x, y, last)) {
last = getAbove(x,y);
draw();
}
}
private void draw() {
if (last == null)
return;
last.setText("+");
}
private void reset() {
last = null;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
tvs[i][j].setText(String.valueOf(i * 5 + j));
}
#Override
public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
reset();
}
#Override
public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
reset();
}
#Override
public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
last = getAbove(event.getRawX(), event.getRawY());
draw();
}
TextView[][] tvs = new TextView[5][5];
TextView last = null;
And make the arraylist into an TextView[5][5]
I have a full-screen custom Gallery. Elements of the gallery have buttons and other interactive areas. Some user interface is done through dialog boxes that pop in front of the gallery; when a dialog box is dismissed, the user is taken back to the gallery.
Most of the time, this works fine. However, sometimes, after a dialog box is dismissed, the buttons stop taking user input. The gallery, on the other hand, still scrolls. What's even more bizarre, as soon as I scroll the gallery, the system processes those clicks I thought failed (pops up a dialog, etc.).
It is easy to say that the main UI thread is locked. Why is it locked? How do I unlock it? Any help will be appreciated. Below is the full code of the class.
UPDATE. One of the elements within the Gallery is a HorizontalScrollView. When I try scroll it, mouse messages come through; I stepped through them and saw that the scrollBy() and invalidate() are properly called. Then I printed out the message queue. The only event that passes through the main loop is 1006, which I assume is the Touch event. The Draw event, the 1000, never makes it. Once I scroll the Gallery back and forth -- lo and behold -- the message queue starts receiving the 1000's, so the HorizontalScrollView scrolls fine!
So the question becomes: what stops the Draw events, and how do I make sure they are sent to the queue?
public class PlayerGallery extends Gallery
{
// 4 buttons to display
private final static int BUT_BIRD = 0;
private final static int BUT_SCORE = 1;
private final static int BUT_ROUND = 2;
private final static int BUT_MOVE = 3;
private final static int N_BUTTONS = 4;
// button images
private final static Drawable[] imgButtons =
{
WonDraw.WW.bird,
WonDraw.WW.scores,
WonDraw.WW.moveSumm,
WonDraw.WW.lastMove,
};
// individual player views
private PlayerView[] views;
// card that was clicked in the current player view
private Card clickedCard = null;
// wonder that was clicked in the current player view
private Player clickedWonderPlayer = null;
// one player
private final class PlayerView extends RelativeLayout
implements OnClickListener
{
// base view ID for the buttons
private final static int BUT_VIEW_ID = 200;
// player to display
final Player player;
// drawing data
private PlayerDisplay pd = null;
// the sub-view on top that shows player's hand
private HandView handView = null;
// button that takes user into bird's view
private final GlassButton[] buttons = new GlassButton[N_BUTTONS];
public PlayerView(Player player)
{
super(WonActivity.W.getApplicationContext());
setBackgroundColor(Color.TRANSPARENT);
this.player = player;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
lp.addRule(ALIGN_PARENT_TOP);
handView = new HandView();
addView(handView, lp);
for (int i = 0; i < buttons.length; ++i)
{
lp = new RelativeLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (i % 2 == 0)
lp.addRule(ALIGN_PARENT_RIGHT);
else
lp.addRule(LEFT_OF, buttons[i - 1].getId());
lp.addRule(BELOW, i / 2 == 0 ? handView.getId() : buttons[i - 2].getId());
GlassButton but = new ImgGlassButton(GlassButton.ROUND, imgButtons[i]);
but.setId(BUT_VIEW_ID + i);
but.setOnClickListener(this);
buttons[i] = but; addView(but, lp);
}
}
// reset for the next player
void reset(boolean useBigCards)
{
pd = WonActivity.W.getDisplay(player.id, useBigCards);
if (useBigCards)
{
handView.pd = pd;
handView.hand = WonActivity.W.getCurrentHand();
handView.setVisibility(VISIBLE);
handView.requestLayout();
handView.scrollTo(0, 0);
}
else
{
handView.pd = null;
handView.hand = null;
handView.setVisibility(GONE);
}
for (int i = BUT_ROUND; i <= BUT_MOVE; ++i)
buttons[i].setEnabled(Table.T.movesAvailable());
invalidate();
}
#Override
protected void dispatchSetPressed(boolean pressed)
{
// if I don't do that, bird button gets pressed when I scroll the gallery!
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN)
{
int x = (int)event.getX();
int y = (int)event.getY();
clickedCard = pd.findSmallCard(x, y);
clickedWonderPlayer = clickedCard == null && pd.isInWonder(x, y) ?
player : null;
}
return super.onTouchEvent(event);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(MeasureSpec.makeMeasureSpec(WonActivity.W.getWidth() - 2, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(WonActivity.W.getHeight(), MeasureSpec.EXACTLY));
setBackgroundColor(Color.TRANSPARENT);
setBackgroundDrawable(WonDraw.W.getWood());
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (pd == null) return;
canvas.save();
pd.draw(canvas, handView.hand, true);
canvas.restore();
}
public void onClick(View v)
{
switch (v.getId() - BUT_VIEW_ID)
{
case BUT_BIRD:
WonActivity.W.switchToBird(player.id);
break;
case BUT_SCORE:
WonActivity.W.showScoreDlg();
break;
case BUT_ROUND:
WonActivity.W.showRoundDlg();
break;
case BUT_MOVE:
break;
}
}
};
// custom adapter for the gallery: provides circular functionality
private class PGAdapter extends BaseAdapter
{
public int getCount()
{
return Integer.MAX_VALUE;
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
return views[position % views.length];
}
};
public PlayerGallery()
{
super(WonActivity.W.getApplicationContext());
setSpacing(0);
setBackgroundColor(Color.TRANSPARENT);
views = new PlayerView[Table.T.getPlayerCount()];
for (int i = 0; i < Table.T.getPlayerCount(); ++i)
views[i] = new PlayerView(Table.T.getPlayer(i));
setAdapter(new PGAdapter());
setHorizontalFadingEdgeEnabled(false);
setVerticalFadingEdgeEnabled(false);
}
// reset for the next player
void changeMovingPlayer()
{
for (int i = 0; i < views.length; ++i)
views[i].reset(i == WonActivity.W.getCurrentPlayerID());
setViewedPlayer(Math.max(WonActivity.W.getCurrentPlayerID(), 0));
}
// set the player whose buildings to view
void setViewedPlayer(int index)
{
int pos = Integer.MAX_VALUE / 2;
pos -= pos % views.length;
setSelection(pos + index);
views[index].requestFocus();
views[index].invalidate();
}
#Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
int kEvent = e2.getX() > e1.getX() ?
KeyEvent.KEYCODE_DPAD_LEFT :
KeyEvent.KEYCODE_DPAD_RIGHT;
onKeyDown(kEvent, null);
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
boolean b = super.onTouchEvent(event);
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_UP:
if (event.getEventTime() - event.getDownTime() < WonActivity.CLICK_MS)
{
if (clickedCard != null)
WonActivity.W.showCardDlg(clickedCard);
else if (clickedWonderPlayer != null)
WonActivity.W.showWonderDlg(clickedWonderPlayer);
}
clickedCard = null;
clickedWonderPlayer = null;
break;
}
return b;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
WonActivity.W.resize(w, h);
super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
}
}