Im having major problem (all of a sudden, it worked before :-)) with drag and drop for my jig-saw puzzle app.
My layout is in 2 relative layouts 1 for the puzzle pieces and 1 for the complete image which I also build with image views.
The imageviews for the complete image is being generated i Async tasks where i load a bitmap into the views. I also assign id's for these views from 1001 to 1006 for the complete image views (if 6 puzzle pieces) and 10001 to 10006 for the puzzle pieces.
After the complete image has been build, i go through the views and assign OnDragListener to all of them. In the same way i assign OnTouchListener to the puzzle pieces in the 1 layout. All seems fine, I can even color the correct listening view when OnTouch is being called for the corresponding puzzle piece.
But my problem is that the drop zone i for some strange reason outside the view which is listening?? It seems as if the all the drop zones for the views in the complete image is being scaled down to a small area near the 1.st listening view?? I know its hard to explain.
The weird thing is that everything is working in emulator (always) and the first time after installation on device (if I choose API 19). If i just close the app and open it again the problem is back??? I notice that the default dragshadow is not resizing the puzzle piece when i drag it (which it does when it works).
Here is the code that sets the listeners
private void setOnDragListeners() {
for(int x=1001;x<=1000+Integer.parseInt(settings_piecesQty);x++)
{
ImageView v = (ImageView) findViewById(x);
v.requestLayout();
DragListener dragListener = new DragListener();
v.setOnDragListener(dragListener);
}
}
private void setOnTouchListeners() {
for(int x=10001;x<=10000+Integer.parseInt(settings_piecesQty);x++)
{
ImageView v = (ImageView) findViewById(x);
v.requestLayout();
onTouchListener touchListener = new onTouchListener();
v.setOnTouchListener(touchListener);
}
}
protected class DragListener implements View.OnDragListener {
public boolean onDrag(View v, DragEvent event) {
int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
if (Integer.parseInt(event.getClipDescription().getLabel().toString()) == v.getId() + 9000) {
return true;
} else
return false;
case DragEvent.ACTION_DRAG_ENTERED:
break;
case DragEvent.ACTION_DRAG_LOCATION:
break;
case DragEvent.ACTION_DRAG_EXITED:
break;
case DragEvent.ACTION_DROP:
draggedImage.setDrawingCacheEnabled(true);
//Bitmap bitmap = Bitmap.createBitmap(draggedImage.getDrawingCache());
v.setForeground(draggedImage.getDrawable());
draggedImage.setDrawingCacheEnabled(false);
piecesLeft--;
if (piecesLeft == 0) {
hasEnded = true;
}
return true;
case DragEvent.ACTION_DRAG_ENDED:
if (!event.getResult()) {
draggedImage.setVisibility(View.VISIBLE);
} else {
if (hasEnded) {
greetings();
}
}
default:
break;
}
return true;
}
}
protected class onTouchListener implements View.OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case (MotionEvent.ACTION_DOWN): {
Log.i("Action_Down : ", String.valueOf(v.getId()));
ClipData.Item item = new ClipData.Item(v.getTag().toString());
ClipData dragData = new ClipData(v.getTag().toString(), new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}, item);
View.DragShadowBuilder myShadow = new View.DragShadowBuilder(v);
v.startDrag(dragData, myShadow, null, 0);
draggedImage = (ImageView) (v);
v.setVisibility(View.INVISIBLE);
return true;
}
}
return false;
}
}
Im building my layout programatically with this code before adding the views
private void buildLayout() {
main_layout = new RelativeLayout(this);
main_layout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryBackground, null));
main_layout.setId(60);
puzzle_piece_layout = new RelativeLayout(this);
puzzle_piece_layout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryBackground, null));
puzzle_piece_layout.setId(1);
RelativeLayout.LayoutParams rlp_puzzle;
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
rlp_puzzle = new RelativeLayout.LayoutParams(windowSizeX / 3, RelativeLayout.LayoutParams.MATCH_PARENT);
rlp_puzzle.addRule(RelativeLayout.START_OF, 60);
}
else{
rlp_puzzle = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,windowSizeY / 3);
rlp_puzzle.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
}
puzzle_piece_layout.setLayoutParams(rlp_puzzle);
main_layout.addView(puzzle_piece_layout, rlp_puzzle);
puzzlePieceView = new View(this);
RelativeLayout.LayoutParams puzzleViewLp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
puzzle_piece_layout.addView(puzzlePieceView, puzzleViewLp);
image_main_area = new RelativeLayout(this);
image_main_area.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark, null));
image_main_area.setId(70);
RelativeLayout.LayoutParams rlp_image_main;
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
rlp_image_main = new RelativeLayout.LayoutParams((windowSizeX - (windowSizeX / 3)), RelativeLayout.LayoutParams.MATCH_PARENT);
rlp_image_main.addRule(RelativeLayout.RIGHT_OF, 1);
}
else{
rlp_image_main = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,(windowSizeY - (windowSizeY / 3)));
rlp_image_main.addRule(RelativeLayout.ABOVE, 1);
}
main_layout.addView(image_main_area, rlp_image_main);
image_layout = new RelativeLayout(this);
image_layout.setBackgroundColor(getResources().getColor(R.color.colorAccent, null));
RelativeLayout.LayoutParams rlp_image = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
rlp_image.addRule(RelativeLayout.CENTER_IN_PARENT);
image_main_area.addView(image_layout, rlp_image);
mProgress = new ProgressBar(this,null,android.R.attr.progressBarStyleHorizontal);
RelativeLayout.LayoutParams plp = new RelativeLayout.LayoutParams(700,500);
plp.addRule(RelativeLayout.CENTER_IN_PARENT);
mProgress.setVisibility(View.VISIBLE);
mProgress.setProgress(0);
mProgress.bringToFront();
main_layout.addView(mProgress,plp);
setContentView(main_layout);
}
I declare my views before i send them to the Async task for processing
final ImageView backgroundView = new ImageView(App.getContext());
final ImageView puzzleView = new ImageView(App.getContext());
And everytime a puzzle piece and complete image piece is loaded from my Async tasks then im setting the id in this method (these methods are called from a OnTaskCompleted listener):
private void initImageViews(ImageView image, int id) {
image.setId(id);
image.setTag(id);
image.setAdjustViewBounds(true);
}
And then they are added to the layouts in these methods
For the puzzle piece:
private void setImagePuzzlePiece(ImageView v) {
int leftMargin;
int topMargin;
Random random = new Random();
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
Float scale = 0.7f;
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
param.addRule(RelativeLayout.ALIGN_BOTTOM);
}
v.setLayoutParams(param);
v.setScaleX(scale);
v.setScaleY(scale);
v.setRotation((float) Math.ceil(Math.random() * (360)));
if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
leftMargin = random.nextInt((windowSizeX/3)-200);
topMargin = random.nextInt((windowSizeY)-200);
}
else {
leftMargin = random.nextInt(windowSizeX-200);
topMargin = random.nextInt((windowSizeY/4)-200);
}
puzzle_piece_layout.addView(v);
v.setX(leftMargin);
v.setY(topMargin);
v.requestLayout();
}
And for the complete image piece:
private void setImageTemplatePiece(ImageView v, int k, int i, int marginX, int marginY) {
RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
if (k > 1) {
param.addRule(RelativeLayout.RIGHT_OF, v.getId()-1);
}
if (i > 1) {
param.addRule(RelativeLayout.BELOW, prevImageIdY[i-2][k-1][0]);
}
param.setMargins(0, 0, -marginX, -marginY);
v.setLayoutParams(param);
image_layout.addView(v);
v.requestLayout();
prevImageIdY[i-1][k-1][0] = v.getId();
}
I have overlapping views so the pieces will match together and form an image without gaps.
I really hope any of this makes any sense and that someone can tell me why the drop zones for the image views i 2 layout is way outside the actual image views! It all worked until i wanted to post the app in playstore and was so stupid as to run Android studios code inspection rather uncritically first. Dont know if this has made the difference but something has happened and i just can't figure it out myself!
I will just include the OnPostExecute method from my Async task in case its relevant:
@Override
protected void onPostExecute(String result) {
final ImageView backgroundView = backgroundPieceReference.get();
if (backgroundView != null) {
backgroundView.setImageBitmap(backgroundBitmap);
}
final ImageView puzzleView = puzzlePieceReference.get();
if (puzzleView != null) {
puzzleView.setImageBitmap(puzzleBitmap);
}
listener.onTaskCompleted(result);
}