I have implemented this spinner in my app. I'm displaying a dialog and I have my spinner in that dialog. I want my spinner to open as the dialog comes up. I have tried performClick() event right after setAdapter() method but it doesn't seem to work.
My code looks like this:
final MaterialBetterSpinner selectBrandForSODRating = dialog.findViewById(R.id.selectBrandForSODspinner);
final ArrayList<Products> brandList = new ArrayList<Products>();
Cursor crsCheckSODData = database.rawQuery(myQuery, null);
if(crsCheckSODData.getCount() > 0){
while (crsCheckSODData.moveToNext()) {
//data...
brandList.add(data);
}
}
crsCheckSODData.close();
final ArrayAdapter<Products> SODBrandAdapter = new ArrayAdapter<Products>(myView.this, android.R.layout.simple_dropdown_item_1line, brandList);
selectBrandForSODRating.setAdapter(SODBrandAdapter);
selectBrandForSODRating.performClick(); //this right here isnt working...
If you are using https://github.com/Lesilva/BetterSpinner, the code is overriding onTouchEvent here, but not overriding onClick. That's why performClick will not work.
You could simulate touch event instead to the view. Here's how:
int[] coords = new int[2];
selectBrandForSODRating.getLocationOnScreen(coords);
float x = (float) coords[0];
float y = (float) coords[1];
// List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
int metaState = 0;
// Obtain MotionEvent object
long downTime1 = SystemClock.uptimeMillis();
long eventTime1 = SystemClock.uptimeMillis() + 100;
MotionEvent motionEventDown = MotionEvent.obtain(
downTime1,
eventTime1,
MotionEvent.ACTION_DOWN,
x,
y,
metaState
);
// Dispatch touch event to view
selectBrandForSODRating.dispatchTouchEvent(motionEventDown);
long downTime2 = SystemClock.uptimeMillis();
long eventTime2 = SystemClock.uptimeMillis() + 100;
MotionEvent motionEventUp = MotionEvent.obtain(
downTime2,
eventTime2,
MotionEvent.ACTION_UP,
x,
y,
metaState
);
// Dispatch touch event to view
selectBrandForSODRating.dispatchTouchEvent(motionEventUp);
You could also directly call the methods from here
selectBrandForSODRating.requestFocus();
selectBrandForSODRating.showDropDown();
But I don't recommend it, because there is another boolean state, isPopUp, that has private access and you can't access.
Related
I have used the following methods but no success
Integer [] location = new Integer[];
view.getLocationOnScreen(location);
getLocationInWindow(int[]) MyCode: int[] locatoins = new int[2];
rulerLyt.findViewById(2).getLocationInWindow(locatoins);
x = locatoins[0];
float y = 0f;
y = locatoins[1];
imgBaby.setTranslationX(x);
imgBaby.setTranslationY(y);
Please give your comment/solution to achieve this
These are easily accessible methods of View class.
int xCordinate = rulerLyt.findViewById(2).getX();
int yCordinate = rulerLyt.findViewById(2).getY();
If you call provided code just after view creation it will return 0. Because view inflation and measuring are async. They happen on different iterations of MainThread. You need to to use ViewTreeObserver as variant.
int[] locatoins = new int[2];
rulerLyt.findViewById(2).getLocationInWindow(locatoins);
float x = locatoins[0];
float y = locatoins[1];
imgBaby.setTranslationX(x);
imgBaby.setTranslationY(y);
Example of usage of ViewTreeObserver
view.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener(){
void onPreDraw(){
view.getViewTreeObserver().removeOnPreDrawListener(this);
//do your staff
return true;
}
})
I was going through some of the awesome Android libraries and I found the Android BrokenView. It's quite simple to use and uses the touch events to show the broken animation. Here's the code that we're required to add in order to enable a View to behave as a BrokenView:
brokenView = BrokenView.add2Window(context);
listener = new BrokenTouchListener.Builder(brokenView).build();
view.setOnTouchListener(listener);
The problem that I've is that I want to perform the broken animation programmatically i.e, without any actual touch events. I tried looking at the source code but couldn't figure out how to achieve that as most of the methods are protected.
Any ideas on how can I do that?
I've achieved this using a motion event. It works, but I'd prefer to call createAnimator() directly, as I don't want the user to be able to trigger the smash via a touch event.
long downTime = SystemClock.uptimeMillis();
long eventTime = SystemClock.uptimeMillis()+1000;
int[] coords = new int[2];
targetView.getLocationOnScreen(coords);
float x = coords[0] + targetView.getWidth()/2;
float y = coords[1] + targetView.getHeight()/2;
MotionEvent motionEvent = MotionEvent.obtain(
downTime,
eventTime,
MotionEvent.ACTION_DOWN,
x,
y,
0
);
mBrokenTouchListener = new BrokenTouchListener.Builder(mBrokenView)
.setEnableArea(mRootView)
.build();
mBrokenTouchListener.onTouch(targetView, motionEvent);
What I'd like to do is this:
Point point = new Point((int)x, (int)y);
BrokenConfig config = new BrokenConfig();
brokenView.createAnimator(mFLTargetView, point, config);
brokenView.setEnable(true);
// or
brokenView.start();
but BrokenConfig is package private, and there's no start() method.
HTH
I am developing an android application where I am creating dynamic Images arrow on relative layout. The images are created on a x,y coordinated of the click area of relative layout. Below is the code the I am using for it.
presciptionScreenArrowImg.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (canSelectMedianStatus == 2) {
if (event == simulationEvent)
return false;
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
Log.e("onTouchListener", "User touch at X:" + x + " Y:" + y);
pointerArrow = new ImageView(getApplication());
pointerArrow.setImageResource(R.drawable.pointer);
pointerArrow.setId(imageArrayTag);
imageArrayTag++;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(40, 40);
params.topMargin = y;
params.leftMargin = x;
pointerArrow.setLayoutParams(params);
presciptionScreenArrowImg.addView(pointerArrow);
long length = 0;
if (action == MotionEvent.ACTION_DOWN) {
// click(v, x, y);
}
}
return false;
}
});
Now, I need is there on button click the last Image drawn should remove first. Basically I need an undo functionality to remove Images as LIFO structure.
let consider presciptionScreenArrowImg is your main layout which contains your all views so for removing
int index=presciptionScreenArrowImg.getChildCount();
if(index>0)
presciptionScreenArrowImg.removeViewAt(index-1);
from above get count of child and remove last view if you have any problem let me know
Store the views in a Queue, and when you add a new view check if the queue is full. If it is, pop a view from the queue, and call presciptionScreenArrowImg.remove(poppedView);
I am working with the ViewPager trying to accomplish some animations. One of them is trying to slide from left to right (default transition of view pager is from right to left). I have done that.
My problem is that I want to "hack" the touch event so I don't need to modify the view pager. For example, for the left to right transition, I will want to make some kind of mirroring with the X in the touch event passed to the view pager.
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
event.setX(Math.abs(event.getX() - getWidth());
return super.onInterceptTouchEvent(event);
}
I finally did it.
public boolean dispatchTouchEvent(MotionEvent event) {
MotionEvent hackedEvent = MotionEvent.obtain(event.getDownTime(),
event.getEventTime(), event.getAction(), (event.getX() - getWidth()) * -1,
event.getY(), event.getMetaState());
boolean result = super.dispatchTouchEvent(hackedEvent);
hackedEvent.recycle();
return result;
};
For people with the same issue and using Kotlin:
I created an extension function to copy the whole MotionEvent in data class style, which allows you to modify certain attributes of it.
E.g.
val modifiedEvent = event.copy(downTime = System.currentTimeMillis())
event.recycle()
Extension function:
/**
* Copies a whole MotionEvent. Use the named parameters to modify certain
values.
* Don't forget to recycle the original event (if it is not used anymore :)
)!
*/
fun MotionEvent.copy(
downTime: Long = getDownTime(),
eventTime: Long = getEventTime(),
action: Int = getAction(),
pointerCount: Int = getPointerCount(),
pointerProperties: Array<MotionEvent.PointerProperties>? =
(0 until getPointerCount())
.map { index ->
MotionEvent.PointerProperties().also { pointerProperties ->
getPointerProperties(index, pointerProperties)
}
}
.toTypedArray(),
pointerCoords: Array<MotionEvent.PointerCoords>? =
(0 until getPointerCount())
.map { index ->
MotionEvent.PointerCoords().also { pointerCoords ->
getPointerCoords(index, pointerCoords)
}
}
.toTypedArray(),
metaState: Int = getMetaState(),
buttonState: Int = getButtonState(),
xPrecision: Float = getXPrecision(),
yPrecision: Float = getYPrecision(),
deviceId: Int = getDeviceId(),
edgeFlags: Int = getEdgeFlags(),
source: Int = getSource(),
flags: Int = getFlags()
): MotionEvent =
MotionEvent.obtain(
downTime,
eventTime,
action,
pointerCount,
pointerProperties,
pointerCoords,
metaState,
buttonState,
xPrecision,
yPrecision,
deviceId,
edgeFlags,
source,
flags
)
Source: https://gist.github.com/sebschaef/b803da53217c88e8c691aeed08602193
I'm trying to detect the virtual keyboard height in Android.
I found a similar topic: Get the height of virtual keyboard in Android
It seems the author found a way to detect the height:
I found a way to get it. After I request to open virtual keyboard, I
send pointer event that I generate. their y coordinate starts from
height of device and decreases.
I don't understand how to do that.
I'll be using the code provided at the link that you posted:
// Declare Variables
int softkeyboard_height = 0;
boolean calculated_keyboard_height;
Instrumentation instrumentation;
// Initialize instrumentation sometime before starting the thread
instrumentation = new Instrumentation();
mainScreenView is your base view, your activity's view. m(ACTION_DOWN) and m1(ACTION_UP) are touch events that are dispatched using Instrumentation#sendPointerSync(MotionEvent). The logic is that a MotionEvent dispatched to where the keyboard is being displayed will cause the following SecurityException:
java.lang.SecurityException: Injecting to another application requires
INJECT_EVENTS permission
So, we start at the bottom of the screen and make our way up (by decrementing y) on every iteration of the loop. For certain number of iterations, we will get a SecurityException (which we'll catch): this would imply that the MotionEvent is happening over the keyboard. The moment y gets small enough (when its just above the keyboard), we'll break out of the loop and calculate the keyboard's height using:
softkeyboard_height = mainScreenView.getHeight() - y;
Code:
Thread t = new Thread(){
public void run() {
int y = mainScreenView.getHeight()-2;
int x = 10;
int counter = 0;
int height = y;
while (true){
final MotionEvent m = MotionEvent.obtain(
SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),
MotionEvent.ACTION_DOWN,
x,
y,
1);
final MotionEvent m1 = MotionEvent.obtain(
SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(),
MotionEvent.ACTION_UP,
x,
y,
1);
boolean pointer_on_softkeyboard = false;
try {
instrumentation.sendPointerSync(m);
instrumentation.sendPointerSync(m1);
} catch (SecurityException e) {
pointer_on_softkeyboard = true;
}
if (!pointer_on_softkeyboard){
if (y == height){
if (counter++ < 100){
Thread.yield();
continue;
}
} else if (y > 0){
softkeyboard_height = mainScreenView.getHeight() - y;
Log.i("", "Soft Keyboard's height is: " + softkeyboard_height);
}
break;
}
y--;
}
if (softkeyboard_height > 0 ){
// it is calculated and saved in softkeyboard_height
} else {
calculated_keyboard_height = false;
}
}
};
t.start();
Instrumentation#sendPointerSync(MotionEvent):
Dispatch a pointer event. Finished at some point after the recipient
has returned from its event processing, though it may not have
completely finished reacting from the event -- for example, if it
needs to update its display as a result, it may still be in the
process of doing that.
Use OnGlobalLayoutListener, it works perfectly for me.