问题
I'm looking for a direction to go with this one. I have a card melding game (Five Kings) which has been up for about 6 months; my latest version 0.9.22 has been stable since March. However, recently I have been getting reports of users unable to drag discards to the discard pile, and the common thread seems to be Samsung S7 with Android 6.0 . When you drag a card from your hand, the places you can drag turn transparent and when you drag over them they go back to normal (alpha=1). Other places you can drag seem to be working ok, but the discard pile doesn't go dim or bright, which makes me think the Drag Event listener isn't working.
Here's the DiscardPileDragEventListener
:
class DiscardPileDragEventListener implements View.OnDragListener {
// This is the method that the system calls when it dispatches a drag event to the
// listener.
@Override
public boolean onDrag(final View v, final DragEvent event) {
//that we are not ready to accept the drag if not at the right point of the play
CardView cv = (CardView)v;
// Defines a variable to store the action type for the incoming event
final int action = event.getAction();
// Handles each of the expected events
switch(action) {
case DragEvent.ACTION_DRAG_STARTED:
// Determines if this View can accept the dragged data
if (cv.isAcceptDrag() && event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
//fades out of the draw pile
cv.startAnimation(Utilities.instantFade(FiveKings.HALF_TRANSPARENT_ALPHA, FiveKings.HALF_TRANSPARENT_ALPHA));
// returns true to indicate that the View can accept the dragged data.
return true;
} else {
//remind user what they should be doing if in the first few rounds
((FiveKings) cv.getContext()).setShowHint(null, FiveKings.HandleHint.SHOW_HINT, FiveKings.GameDifficulty.EASY);
// Returns false. During the current drag and drop operation, this View will
// not receive events again until ACTION_DRAG_ENDED is sent.
return false;
}
case DragEvent.ACTION_DRAG_ENTERED:
cv.clearAnimation();
return true;
case DragEvent.ACTION_DRAG_LOCATION:
// Ignore the event
return true;
case DragEvent.ACTION_DRAG_EXITED:
cv.startAnimation(Utilities.instantFade(FiveKings.HALF_TRANSPARENT_ALPHA, FiveKings.HALF_TRANSPARENT_ALPHA));
return true;
case DragEvent.ACTION_DROP:
cv.clearAnimation();
// Gets the item containing the dragged data
ClipData.Item item = event.getClipData().getItemAt(0); //this is the View index to recover which card
// Gets the text data from the item.
String dragData = item.getText().toString();
//Handle exception here and return false (drop wasn't handled) if it wasn't found
int iView = -1;
try {
iView = Integer.parseInt(dragData);
}catch (NumberFormatException e) {
return false;
}
return ((FiveKings)cv.getContext()).discardedCard(iView);
case DragEvent.ACTION_DRAG_ENDED:
if (cv.isAcceptDrag()) cv.clearAnimation();
return true;
// An unknown action type was received.
default:
Log.e("DiscardPileDragEventListener", "Unknown action type received by OnDragListener.");
}
return false;
}
}
Here's the code snippets which sets up the actual dragged card; in this CardView is a subclass of ImageView:
for (Card card : meld) {
//highlight wildcards unless no dragging (Computer turn, or Human final turn)
CardView cv = new CardView(this, card, iView, allowDragging ? highlightWildCardRank : null);
cv.setTag(iView); //allows us to pass the index into the dragData without dealing with messy object passing
...
cv.bringToFront();
cv.setClickable(false); //TODO:B: Allow selection by clicking for multi-drag?
if (allowDragging) {//no dragging of computer cards or Human cards after final turn
cv.setOnDragListener(new CardViewDragEventListener()); //needed per-card to reset the dragged card to normal visibility (alpha)
cv.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) return false;
// Create a new ClipData using the tag as a label, the plain text MIME type, and
// the string containing the View index. This will create a new ClipDescription object within the
// ClipData, and set its MIME type entry to "text/plain"
ClipData dragData = ClipData.newPlainText("Discard", v.getTag().toString());
View.DragShadowBuilder cardDragShadow = new CardViewDragShadowBuilder(v);
v.startAnimation(Utilities.instantFade(FiveKings.HALF_TRANSPARENT_ALPHA, FiveKings.HALF_TRANSPARENT_ALPHA));
// Starts the drag
v.startDrag(dragData, cardDragShadow, null, 0);
return true;
}//end onClick
});
}//end if allowDragging
...
And in the onCreate, I set up the Discard Pile onDragListener:
...
mDiscardPile.setOnDragListener(new DiscardPileDragEventListener());
...
One wrinkle is that I also have a an onDragListener in the parent view of the Discard Pile, to provide a message as you drag your card to the Discard Pile. This has worked fine in my testing, but I just wonder if it's related somehow.
Would appreciate any suggestions as to which direction to head.
回答1:
It turns out that Samsung introduced a feature called Game Tuner for S7 and back-ported it to S6 and other devices. It automatically changes the Resolution Ratio for any installed app marked as a "Game" in the market. This works great for a graphics driven game, but completely screws up a card game like mine with Drag-and-drop. Note this happens even if you never go into the Game Tuner app.
So, if you experience this with your game or app, ask if the user has Game Tuner installed and ask them to set Resolution Ratio to 100% (they can do that on a game-by-game basis).
UPDATE Mar2017: I now have 99% of the solution. Even WITHOUT Game Tuner installed, Samsung scales a game (apparently to 75%). So you HAVE to install Game Tuner and then reset the Resolution to 100% to make drag-and-drop work properly.
The 1% I don't have is why they would do something stupid like this.
回答2:
Samsung Display Scaling option: It shrinks things down on certain screens.
For instance, on the home screen when you open a folder you see more icons.
I believe Samsung recently (July 2016) released an OTA update which has this feature. If this feature is available in the Settings/Display it means the OTA update has been installed which appears to solve the drag and drop issue.
来源:https://stackoverflow.com/questions/38044129/drageventlistener-not-working-on-samsung-s7-6-0