Well, at the beginning of the Implementation of ItemTouchHelper, I chose to use only the Swipe function from it. Everything worked - with the help of Swipe I could delete items in RecyclerView etc. But then I thought I'd add up-down movement so that the user could change the order in which the item appears in the list.
Then the problems began - the user can change the order in which items are displayed, but can no longer:
Scroll RecyclerView (even if changing item up-down position is disabled)
Swipe functions have stopped working - onSwiped does not return the side (ItemTouchHelper.LEFT, ItemTouchHelper.RIGHT) in which the item was swiped
I changed the View on which is trigger OnStartDragListener from _view to just ImageView and I can scroll now but there are now other problems:
Swipe works on that ImageView too - I want to be able to swipe item whereever user click on item (_view)
Swipe functions still doesn't work - onSwiped does not return the side (ItemTouchHelper.LEFT, ItemTouchHelper.RIGHT) in which the item was swiped
Video how the problem looks
FIXED
I Changed
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags =
mDraggable
? ItemTouchHelper.UP
| ItemTouchHelper.DOWN
| ItemTouchHelper.START
| ItemTouchHelper.END
: 0;
if (mDraggable) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
} else {
dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlags, 0);
}
To
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;
int swipeFlags = 0;
if (mDraggable) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
return makeMovementFlags(dragFlags, 0);
} else {
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(0, swipeFlags);
}
}
RecyclerView Adapter:
package tw.codeassist.plus;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import tw.codeassist.plus.SwipeToDeleteCallback;
public class CodeAdapter extends RecyclerView.Adapter<CodeAdapter.ViewHolder> implements SwipeToDeleteCallback.ItemTouchHelperAdapter {
ArrayList<HashMap<String, Object>> _data;
Context context;
SharedPreferences snippets;
OnItemClickListener mItemClickListener;
private static final int TYPE_ITEM = 0;
//private final LayoutInflater mInflater;
private final tw.codeassist.plus.SwipeToDeleteCallback.OnStartDragListener mDragStartListener;
public CodeAdapter(
android.content.Context appCont,
ArrayList<HashMap<String, Object>> _arr,
tw.codeassist.plus.SwipeToDeleteCallback.OnStartDragListener dragListner) {
_data = _arr;
context = appCont;
mDragStartListener = dragListner;
snippets = context.getSharedPreferences("snippets", Activity.MODE_PRIVATE);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater _inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View _v = _inflater.inflate(R.layout.codesnippets, null);
RecyclerView.LayoutParams _lp =
new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
_v.setLayoutParams(_lp);
return new ViewHolder(_v);
}
#Override
public void onBindViewHolder(ViewHolder _holder, final int _position) {
View _view = _holder.itemView;
final androidx.cardview.widget.CardView cardview1 = _view.findViewById(R.id.cardview1);
final LinearLayout main_linear = (LinearLayout) _view.findViewById(R.id.main_linear);
final LinearLayout color_linear = (LinearLayout) _view.findViewById(R.id.color_linear);
final LinearLayout linear3 = (LinearLayout) _view.findViewById(R.id.linear3);
final TextView title_txt = (TextView) _view.findViewById(R.id.title_txt);
final TextView desc_txt = (TextView) _view.findViewById(R.id.desc_txt);
title_txt.setTypeface(
Typeface.createFromAsset(context.getAssets(), "fonts/product_sans_bold.ttf"), 0);
desc_txt.setTypeface(
Typeface.createFromAsset(context.getAssets(), "fonts/product_sans_regular.ttf"), 0);
title_txt.setText(_data.get((int) _position).get("Title").toString());
desc_txt.setText(_data.get((int) _position).get("Description").toString());
color_linear.setBackgroundColor(
Color.parseColor(_data.get((int) _position).get("Color").toString()));
RecyclerView.LayoutParams _lp =
new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
_view.setLayoutParams(_lp);
_view.setOnTouchListener(
new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
mDragStartListener.onStartDrag(_holder);
}
return false;
}
});
}
#Override
public int getItemCount() {
return _data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, ItemTouchHelperViewHolder {
public ViewHolder(View v) {
super(v);
v.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(v, getAdapterPosition());
}
}
#Override
public void onItemSelected() {
itemView.setBackgroundColor(Color.LTGRAY);
}
#Override
public void onItemClear() {
itemView.setBackgroundColor(0);
}
}
#Override
public void onItemDismiss(int position) {
_data.remove(position);
notifyItemRemoved(position);
}
#Override
public boolean onItemMove(int fromPosition, int toPosition) {
Log.d("onItemMove", "Log position" + fromPosition + " " + toPosition);
if (fromPosition < _data.size() && toPosition < _data.size()) {
if (fromPosition < toPosition) {
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(_data, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(_data, i, i - 1);
}
}
Collections.reverse(_data);
snippets.edit().putString("CodeSnippets", new Gson().toJson(this._data)).commit();
notifyItemMoved(fromPosition, toPosition);
}
return true;
}
public void showMessage(String message) {
Toast.makeText((Activity) context, message, Toast.LENGTH_SHORT).show();
}
public void updateList(ArrayList<HashMap<String, Object>> list) {
_data = list;
notifyDataSetChanged();
}
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public void setOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
public void removeAt(int position) {
_data.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, _data.size());
}
public interface ItemTouchHelperViewHolder {
void onItemSelected();
void onItemClear();
}
}
ItemTouchHelper Callback
package tw.codeassist.plus;
import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.Gson;
public class SwipeToDeleteCallback extends ItemTouchHelper.Callback {
private CodeAdapter mAdapter;
Context context;
private SharedPreferences snippets;
private Drawable icon;
private Drawable icon2;
private GradientDrawable background; // ColorDrawable Before
boolean mDraggable = true;
public SwipeToDeleteCallback(Context con, CodeAdapter adapter, boolean canEdit) {
mAdapter = adapter;
context = con;
setDraggable(canEdit);
DisplayMetrics dm = new DisplayMetrics();
((Activity) con).getWindowManager().getDefaultDisplay().getMetrics(dm);
float densityScale = dm.density;
// DELETE ICON
Drawable dr = con.getResources().getDrawable(R.drawable.ic_delete);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
icon =
new BitmapDrawable(
con.getResources(),
Bitmap.createScaledBitmap(
bitmap,
(int) (150 * densityScale / 3),
(int) (150 * densityScale / 3),
true));
// COPY ICON
Drawable dr2 = con.getResources().getDrawable(R.drawable.ic_copy);
Bitmap bitmap2 = ((BitmapDrawable) dr2).getBitmap();
icon2 =
new BitmapDrawable(
con.getResources(),
Bitmap.createScaledBitmap(
bitmap2,
(int) (200 * densityScale / 3),
(int) (200 * densityScale / 3),
true));
// TO INIT THE background
int startColor = Color.WHITE;
int endColor = Color.RED;
background =
new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, new int[] {startColor, endColor});
background.setCornerRadius(20);
}
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags =
mDraggable
? ItemTouchHelper.UP
| ItemTouchHelper.DOWN
| ItemTouchHelper.START
| ItemTouchHelper.END
: 0;
if (mDraggable) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
} else {
dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlags, 0);
}
public void setDraggable(boolean value) {
mDraggable = value;
}
#Override
public boolean isLongPressDragEnabled() {
return true;
}
#Override
public boolean onMove(
RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
if (mDraggable) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
} else {
return false;
}
}
void showMessage(String message) {
Toast.makeText(((Activity) context), message, Toast.LENGTH_SHORT).show();
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
showMessage(String.valueOf(direction));
if (direction == 8) { // RIGHT TO LEFT
// copy
VibrateNotify(200);
String getCode = mAdapter._data.get((int) position).get("Code").toString();
CharSequence code = getCode;
LinearLayout linearSnack =
(LinearLayout) ((FragmentActivity) context).findViewById(R.id.linear1);
((ClipboardManager) context.getSystemService(context.CLIPBOARD_SERVICE))
.setPrimaryClip(ClipData.newPlainText("", code));
com.google.android.material.snackbar.Snackbar.make(
context,
linearSnack,
"Code Copied!",
com.google.android.material.snackbar.Snackbar.LENGTH_LONG)
.setAction(
"",
new View.OnClickListener() {
#Override
public void onClick(View _view) {}
})
.show();
mAdapter.notifyItemChanged(position);
} else if (direction == 4) { // 4 = LEFT TO RIGHT
// delete
mAdapter.removeAt(position);
VibrateNotify(500);
snippets = context.getSharedPreferences("snippets", context.MODE_PRIVATE);
snippets.edit().putString("CodeSnippets", new Gson().toJson(mAdapter._data)).commit();
mAdapter.notifyItemRemoved(position);
}
}
public void VibrateNotify(long duration) {
Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(duration, VibrationEffect.EFFECT_DOUBLE_CLICK));
} else {
// deprecated in API 26
v.vibrate(duration);
}
}
#Override
public void onChildDraw(
Canvas c,
RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
float dX,
float dY,
int actionState,
boolean isCurrentlyActive) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
View itemView = viewHolder.itemView;
int backgroundCornerOffset = 15; // so background is behind the rounded corners of itemView
int alpha = 128;
int colorGreen = Color.parseColor("#FF0000FF");
icon.setAlpha(alpha);
icon2.setAlpha(alpha);
int iconMargin = (itemView.getHeight() - icon.getIntrinsicHeight()) / 3;
int iconTop = itemView.getTop() + (itemView.getHeight() - icon.getIntrinsicHeight()) / 2;
int iconBottom = iconTop + icon.getIntrinsicHeight();
if (dX > 0) { // Swiping to the right
int iconLeft = itemView.getLeft() + iconMargin; // icon.getIntrinsicWidth()
int iconRight = iconLeft + icon.getIntrinsicWidth(); // itemView.getLeft()
icon2.setBounds(iconLeft, iconTop, iconRight, iconBottom);
int START = 0xFF90A4AE;
int END = Color.TRANSPARENT;
background =
new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, new int[] {START, END});
background.setCornerRadius(20);
background.setBounds(
itemView.getLeft(),
itemView.getTop(),
itemView.getLeft() + ((int) dX) + backgroundCornerOffset,
itemView.getBottom());
} else if (dX < 0) { // Swiping to the left
int iconLeft = itemView.getRight() - iconMargin - icon.getIntrinsicWidth();
int iconRight = itemView.getRight() - iconMargin;
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom);
int START = Color.TRANSPARENT;
int END = 0xFFE57373;
background =
new GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT, new int[] {START, END});
background.setCornerRadius(20);
background.setBounds(
itemView.getRight() + ((int) dX) - backgroundCornerOffset,
itemView.getTop(),
itemView.getRight(),
itemView.getBottom());
} else { // view is unSwiped
icon.setBounds(0, 0, 0, 0);
icon2.setBounds(0, 0, 0, 0);
background.setBounds(0, 0, 0, 0);
}
background.setStroke(25, Color.TRANSPARENT);
// background.setPadding(0, paddingTop, 0, paddingBottom); //left, top, right, bottom
background.draw(c);
icon.draw(c);
icon2.draw(c);
}
public interface OnStartDragListener {
void onStartDrag(RecyclerView.ViewHolder viewHolder);
}
public interface ItemTouchHelperAdapter {
boolean onItemMove(int fromPosition, int toPosition);
void onItemDismiss(int position);
}
}
Fragment where the RecyclerView is:
package tw.codeassist.plus;
import android.animation.*;
import android.app.*;
import android.app.Activity;
import android.content.*;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.*;
import android.graphics.*;
import android.graphics.Typeface;
import android.graphics.drawable.*;
import android.media.*;
import android.net.*;
import android.os.*;
import android.text.*;
import android.text.style.*;
import android.util.*;
import android.view.*;
import android.view.View;
import android.view.View.*;
import android.view.animation.*;
import android.webkit.*;
import android.widget.*;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.*;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.*;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.github.angads25.filepicker.*;
import com.github.dhaval2404.colorpicker.*;
import com.google.android.flexbox.*;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.zip4j.*;
import io.github.rosemoe.sora.*;
import java.io.*;
import java.text.*;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.*;
import org.json.*;
public class TutorialsFragmentActivity extends Fragment
implements SwipeToDeleteCallback.OnStartDragListener {
private FloatingActionButton _fab;
private CodeAdapter codeAdapter;
private ArrayList<HashMap<String, Object>> dataToShow = new ArrayList<>();
public LinearLayout linear1;
private TextView textview1;
private TextView goneTxt;
private TextView editBttn;
private RecyclerView recyclerView;
private LinearLayout noCodesView;
TutorialsFragmentActivity tfa = this;
private SharedPreferences.OnSharedPreferenceChangeListener listener;
private Intent intent = new Intent();
private SharedPreferences snippets;
private SharedPreferences settings;
private ItemTouchHelper itemTouchHelper;
boolean isEditMode = false;
#NonNull
#Override
public View onCreateView(
#NonNull LayoutInflater _inflater,
#Nullable ViewGroup _container,
#Nullable Bundle _savedInstanceState) {
View _view = _inflater.inflate(R.layout.tutorials_fragment, _container, false);
initialize(_savedInstanceState, _view);
com.google.firebase.FirebaseApp.initializeApp(getContext());
initializeLogic();
return _view;
}
private void initialize(Bundle _savedInstanceState, View _view) {
_fab = _view.findViewById(R.id._fab);
settings = getContext().getSharedPreferences("settings", Activity.MODE_PRIVATE);
noCodesView = _view.findViewById(R.id.linearNoCodes);
linear1 = _view.findViewById(R.id.linear1);
goneTxt = _view.findViewById(R.id.txGone);
editBttn = _view.findViewById(R.id.edit);
textview1 = _view.findViewById(R.id.textview1);
recyclerView = _view.findViewById(R.id.recyclerView);
snippets = getContext().getSharedPreferences("snippets", Activity.MODE_PRIVATE);
listener =
new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals("CodeSnippets")) {
if (settings.getString("ShouldRefresh", "") == "true") {
itemTouchHelper.attachToRecyclerView(null);
dataToShow =
new Gson()
.fromJson(
snippets.getString("CodeSnippets", ""),
new TypeToken<
ArrayList<
HashMap<
String,
Object>>>() {}.getType());
Collections.reverse(dataToShow);
codeAdapter = new CodeAdapter(getContext(), dataToShow, tfa);
recyclerView.setAdapter(codeAdapter);
//recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
itemTouchHelper =
new ItemTouchHelper(
new SwipeToDeleteCallback(
getContext(), codeAdapter, false));
itemTouchHelper.attachToRecyclerView(recyclerView);
settings.edit().putString("ShouldRefresh", "false").commit();
} else {
}
}
}
};
snippets.registerOnSharedPreferenceChangeListener(listener);
goneTxt.setVisibility(View.INVISIBLE);
editBttn.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View _view) {
if (!isEditMode) {
isEditMode = true;
editBttn.setText("Close");
goneTxt.setText("Close");
} else {
isEditMode = false;
editBttn.setText("Edit");
goneTxt.setText("Edit");
}
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper =
new ItemTouchHelper(
new SwipeToDeleteCallback(
getContext(), codeAdapter, isEditMode));
itemTouchHelper.attachToRecyclerView(recyclerView);
}
});
_fab.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View _view) {
editBttn.setText("Edit");
goneTxt.setText("Edit");
isEditMode = false;
itemTouchHelper.attachToRecyclerView(null);
itemTouchHelper =
new ItemTouchHelper(
new SwipeToDeleteCallback(
getContext(), codeAdapter, isEditMode));
itemTouchHelper.attachToRecyclerView(recyclerView);
intent.setClass(
getContext().getApplicationContext(), AddSnippetActivity.class);
startActivity(intent);
}
});
}
#Override
public void onResume() {
}
#Override
public void onStart() {
super.onStart();
}
public void onPause() {
super.onPause();
}
private void initializeLogic() {
{
android.graphics.drawable.GradientDrawable SketchUi =
new android.graphics.drawable.GradientDrawable();
int clrs[] = {0xFFFFFFFF, 0xFFE0E0E0};
SketchUi =
new android.graphics.drawable.GradientDrawable(
android.graphics.drawable.GradientDrawable.Orientation.TOP_BOTTOM,
clrs);
linear1.setBackground(SketchUi);
}
noCodesView.setVisibility(View.GONE);
textview1.setTypeface(
Typeface.createFromAsset(getContext().getAssets(), "fonts/product_sans_bold.ttf"),
0);
dataToShow =
new Gson()
.fromJson(
snippets.getString("CodeSnippets", ""),
new TypeToken<ArrayList<HashMap<String, Object>>>() {}.getType());
Collections.reverse(dataToShow);
codeAdapter = new CodeAdapter(this.getContext(), dataToShow, this);
recyclerView.setAdapter(codeAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
itemTouchHelper =
new ItemTouchHelper(new SwipeToDeleteCallback(getContext(), codeAdapter, false));
itemTouchHelper.attachToRecyclerView(recyclerView);
removeScrollBar(recyclerView);
if (dataToShow.size() == 0) {
noCodesView.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else {
noCodesView.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
}
}
public void removeScrollBar(View _view) {
_view.setVerticalScrollBarEnabled(false);
_view.setHorizontalScrollBarEnabled(false);
}
#Override
public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
itemTouchHelper.startDrag(viewHolder);
}
}
FIXED
I Changed
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags =
mDraggable
? ItemTouchHelper.UP
| ItemTouchHelper.DOWN
| ItemTouchHelper.START
| ItemTouchHelper.END
: 0;
if (mDraggable) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
} else {
dragFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
}
return makeMovementFlags(dragFlags, 0);
}
To
#Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
int dragFlags = 0;
int swipeFlags = 0;
if (mDraggable) {
dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
return makeMovementFlags(dragFlags, 0);
} else {
swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
return makeMovementFlags(0, swipeFlags);
}
}
Hey guys I'm trying to use this library (https://github.com/davemorrissey/subsampling-scale-image-view) and I tried out the example mentioned about PinView but I don't get the map displayed nor any Marker. ( the error says cannot cast Subsampling ImageView as PinView how do you solve this ?
MainActivity.java
package com.ascot.mxiv.mapzone;
import android.graphics.PointF;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import com.davemorrissey.labs.subscaleview.ImageSource;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PinView imageView = findViewById(R.id.imageView);
imageView.setImage(ImageSource.resource(R.drawable.completemap1).tilingDisabled());
imageView.setPin(new PointF(460f, 320f));
}
}
PinView.java ( no changes made other than the import test.T.drawable as i dont understand it ) and help would be appreciated :D .
import android.content.Context;
import android.graphics.*;
import android.util.AttributeSet;
import android.widget.Toast;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
//import com.davemorrissey.labs.subscaleview.test.R.drawable;
public class PinView extends SubsamplingScaleImageView {
private final Paint paint = new Paint();
private final PointF vPin = new PointF();
private PointF sPin;
private Bitmap pin;
Context context;
public PinView(Context context) {
this(context, null);
this.context = context;
}
public PinView(Context context, AttributeSet attr) {
super(context, attr);
this.context = context;
initialise();
}
public void setPin(PointF sPin) {
this.sPin = sPin;
initialise();
invalidate();
}
private void initialise() {
float density = getResources().getDisplayMetrics().densityDpi;
pin = BitmapFactory.decodeResource(this.getResources(), R.drawable.marker);
float w = (density/420f) * pin.getWidth();
float h = (density/420f) * pin.getHeight();
pin = Bitmap.createScaledBitmap(pin, (int)w, (int)h, true);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Don't draw pin before image is ready so it doesn't move around during setup.
if (!isReady()) {
return;
}
paint.setAntiAlias(true);
if (sPin != null && pin != null) {
sourceToViewCoord(sPin, vPin);
float vX = vPin.x - (pin.getWidth()/2);
float vY = vPin.y - pin.getHeight();
canvas.drawBitmap(pin, vX, vY, paint);
Toast.makeText(context,"works ? ", Toast.LENGTH_SHORT).show();
}
}
}
The problem is your in your layout, you should use PinView instead of SubsamplingScaleImageView as shown in the snippet below.
..
<com.example.myapp.PinView
android:id="#+id/floorplan_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
I'm trying to animate a card flip and then fling it away with an animation. For the most part I've completed that. The problem is I can't get the card to reliably be removed.
Question: How can I reliably delete a View after animation on it is complete? (also I'm using AnimationSet, so this may change things)
Here is what my code looks like.
flingCardAway(the problem area)
private void flingCardAway(){
final View cardContainer = findViewById(R.id.card_container);
ViewCompat.setTranslationZ(cardContainer, 1.0f);
AnimationSet anim = new AnimationSet(true);
RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
rotate1.setStartOffset(100);
rotate1.setDuration(500);
anim.addAnimation(rotate1);
TranslateAnimation trans1 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
trans1.setDuration(600);
anim.addAnimation(trans1);
AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
opacity1.setDuration(400);
opacity1.setStartOffset(200);
anim.addAnimation(opacity1);
cardContainer.setAnimation(anim);
cardContainer.setVisibility(View.VISIBLE);
anim.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
final View cardContainer2 = findViewById(R.id.card_container);
((ViewGroup)cardContainer2.getParent()).removeView(cardContainer2);
}
});
}
Full class for reference
Study.java
package com.example.trevorwood.biggles.study;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.example.trevorwood.biggles.R;
public class Study extends AppCompatActivity {
LinearLayout mFlipCardLinearLayout;
LinearLayout mCardFlippedButtons;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_study);
Intent intent = getIntent();
// String value = intent.getStringExtra("key");
Toolbar toolbar = (Toolbar) findViewById(R.id.study_toolbar);
toolbar.setTitleTextColor(Color.WHITE);//0xAARRGGBB
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mFlipCardLinearLayout = (LinearLayout) findViewById(R.id.flip_card_linear_layout);
mCardFlippedButtons = (LinearLayout) findViewById(R.id.card_flipped_buttons);
final Drawable upArrow = getResources().getDrawable(R.drawable.ic_back_arrow);
upArrow.setColorFilter(getResources().getColor(R.color.colorWhite), PorterDuff.Mode.SRC_ATOP);
getSupportActionBar().setHomeAsUpIndicator(upArrow);
makeNewCard();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
super.onBackPressed();
}
public void onCardClick(View view) {
flipCard();
}
public void onCardFlippedButtonsClick(View view) {
Integer numberPressed;
switch (view.getId()){
case R.id.color_button_1:numberPressed = 1;break;
case R.id.color_button_2:numberPressed = 2;break;
case R.id.color_button_3:numberPressed = 3;break;
case R.id.color_button_4:numberPressed = 4;break;
case R.id.color_button_5:numberPressed = 5;break;
default:numberPressed = 0;
}
saveCardStats(numberPressed);
flingCardAway();
resetForNewCard();
makeNewCard();
}
private void flipCard() {
FrameLayout cardFrame = (FrameLayout) findViewById(R.id.card_frame);
Integer childCount = cardFrame.getChildCount();
Log.d("Simple","childCount: "+childCount);
View cardContainer = findViewById(R.id.card_container);
View cardFace = findViewById(R.id.card_front);
View cardBack = findViewById(R.id.card_back);
FlipAnimation flipAnimation = new FlipAnimation(cardFace, cardBack);
if (cardFace.getVisibility() == View.GONE) {
mFlipCardLinearLayout.setVisibility(View.VISIBLE);
mCardFlippedButtons.setVisibility(View.GONE);
flipAnimation.reverse();
}else{
mFlipCardLinearLayout.setVisibility(View.GONE);
mCardFlippedButtons.setVisibility(View.VISIBLE);
}
cardContainer.startAnimation(flipAnimation);
}
private void saveCardStats(Integer numberPressed){
}
private void flingCardAway(){
final View cardContainer = findViewById(R.id.card_container);
ViewCompat.setTranslationZ(cardContainer, 1.0f);
AnimationSet anim = new AnimationSet(true);
RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
rotate1.setStartOffset(100);
rotate1.setDuration(500);
anim.addAnimation(rotate1);
TranslateAnimation trans1 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
trans1.setDuration(600);
anim.addAnimation(trans1);
AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
opacity1.setDuration(400);
opacity1.setStartOffset(200);
anim.addAnimation(opacity1);
cardContainer.setAnimation(anim);
cardContainer.setVisibility(View.VISIBLE);
anim.setAnimationListener(new Animation.AnimationListener(){
#Override
public void onAnimationStart(Animation arg0) {
}
#Override
public void onAnimationRepeat(Animation arg0) {
}
#Override
public void onAnimationEnd(Animation arg0) {
final View cardContainer2 = findViewById(R.id.card_container);
((ViewGroup)cardContainer2.getParent()).removeView(cardContainer2);
}
});
}
private void resetForNewCard(){
mFlipCardLinearLayout.setVisibility(View.VISIBLE);
mCardFlippedButtons.setVisibility(View.GONE);
}
private void makeNewCard(){
FrameLayout cardFrame = (FrameLayout) findViewById(R.id.card_frame);
Integer childCount = cardFrame.getChildCount();
Log.d("Simple","childCount: "+childCount);
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.study_card, cardFrame);
}
}
FlipAnimation.java (not as important, just a reference)
package com.example.trevorwood.biggles.study;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
public class FlipAnimation extends Animation {
private Camera camera;
private View fromView;
private View toView;
private float centerX;
private float centerY;
private boolean forward = true;
/**
* Creates a 3D flip animation between two views.
*
* #param fromView First view in the transition.
* #param toView Second view in the transition.
*/
public FlipAnimation(View fromView, View toView) {
this.fromView = fromView;
this.toView = toView;
setDuration(300);
setFillAfter(false);
setInterpolator(new AccelerateDecelerateInterpolator());
}
public void reverse() {
forward = false;
View switchView = toView;
toView = fromView;
fromView = switchView;
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
centerX = width / 2;
centerY = height / 2;
camera = new Camera();
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
// Angle around the y-axis of the rotation at the given time
// calculated both in radians and degrees.
final double radians = Math.PI * interpolatedTime;
float degrees = (float) (180.0 * radians / Math.PI);
// Once we reach the midpoint in the animation, we need to hide the
// source view and show the destination view. We also need to change
// the angle by 180 degrees so that the destination does not come in
// flipped around
if (interpolatedTime >= 0.5f) {
degrees -= 180.f;
fromView.setVisibility(View.GONE);
toView.setVisibility(View.VISIBLE);
}
if (forward)
degrees = -degrees; //determines direction of rotation when flip begins
final Matrix matrix = t.getMatrix();
camera.save();
camera.translate(0, 0, Math.abs(degrees)*6);
camera.getMatrix(matrix);
camera.rotateY(degrees);
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
}
I saw this, it helped but didn't solve my problem. End animation event android
I saw this too, but am not sure how to implement it into my own project. android animation is not finished in onAnimationEnd
The google docs all point to this link but this isn't reliable under rapid clicks.
This worked for me. Even though if you were to think about it, it probably shouldn't work. (It 100% would not work if converted to JavaScript, as the view is being removed before the animation has ended.) Perhaps somebody with more Android experience can explain why this works.
My hypothesis on why this works (please keep in mind, this is just a guess): is that Android's animations actually turn the view into something else entirely, while the original view is turned transparent. Then when the animation is ended, the animation view is deleted and the original view is turned back to visible.
private void flingCardAway(){
View cardContainer = findViewById(R.id.card_container);
ViewCompat.setTranslationZ(cardContainer, 1.0f);
AnimationSet anim = new AnimationSet(true);
RotateAnimation rotate1 = new RotateAnimation(0,-45, Animation.RELATIVE_TO_SELF,0.5f , Animation.RELATIVE_TO_SELF,0.5f );
rotate1.setStartOffset(10);
rotate1.setDuration(500);
anim.addAnimation(rotate1);
TranslateAnimation trans1 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.2f, Animation.RELATIVE_TO_PARENT, -0.0f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
trans1.setDuration(100);
anim.addAnimation(trans1);
TranslateAnimation trans2 = new TranslateAnimation(Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, -0.1f, Animation.RELATIVE_TO_PARENT, 0.0f, Animation.RELATIVE_TO_PARENT, 0.0f);
trans2.setStartOffset(100);
trans2.setDuration(100);
anim.addAnimation(trans2);
AlphaAnimation opacity1 = new AlphaAnimation(1.0f, 0.0f);
opacity1.setDuration(300);
opacity1.setStartOffset(300);
anim.addAnimation(opacity1);
cardContainer.setAnimation(anim);
mCardFrame.removeAllViews();
}
When I'm setting the margins of this ImageButton, it distorts the size of the image. Why is this happening?
Code:
package com.example.e99900004533.candycollector;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.graphics.Point;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Display;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.LinearLayout;
import android.view.ViewGroup.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.EditText;
import android.widget.ImageButton;
import java.util.Random;
public class MainActivity extends ActionBarActivity {
public EditText collectedTextEdit;
public ImageButton candyEdit;
public int collected = 0;
public int screenWidth = 300;
public int screenHeight = 300;
Random random = new Random();
public boolean running = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
collectedTextEdit = (EditText) findViewById(R.id.collectedText);
candyEdit = (ImageButton) findViewById(R.id.candy);
collectedTextEdit.setText("Collected: " + collected);
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
addListenerOnButton();
}
public void addListenerOnButton() {
candyEdit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
collected += 1;
collectedTextEdit.setText("Collected: " + collected);
int candyX = random.nextInt(screenWidth - 50);
int candyY = random.nextInt(screenHeight - 50);
System.out.println(candyX + " : " + candyY);
MarginLayoutParams marginParams = new MarginLayoutParams(candyEdit.getLayoutParams());
marginParams.setMargins(candyX, candyY, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams);
candyEdit.setLayoutParams(layoutParams);
if (candyX > screenWidth) {
screenWidth -= 50;
layoutParams.setMargins(candyX, candyY, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
candyEdit.setLayoutParams(layoutParams);
}
if (candyY > screenHeight) {
screenHeight -= 50;
layoutParams.setMargins(candyX, candyY, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
candyEdit.setLayoutParams(layoutParams);
}
//while (running == true) {
//candyY -= 1;
//layoutParams.setMargins(candyX, candyY, candyX, candyY);
//candyEdit.setLayoutParams(layoutParams);
//}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Here is the ImageButton code:
<ImageButton
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/candy"
android:background="#drawable/candy"
android:contentDescription="#string/candyImg"
android:clickable="true"
android:layout_below="#+id/collectedText"
android:layout_alignRight="#+id/collectedText"
android:layout_alignEnd="#+id/collectedText" />
Also can anyone explain, or give resources, on how setting margins really works. BTW using Android Api level 15 - 22.
Please Help!
I need help regarding the viewpager. Basically I have a viewpager contained in a page container:
package com.example.CustomViews;
/**
* Created by imrankhan on 4/29/2015.
*/
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.graphics.Point;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.example.imrankhan.newlawdojo.DashboardActivity;
import com.example.imrankhan.newlawdojo.QuizActivity;
import com.example.imrankhan.newlawdojo.R;
/**
* PagerContainer: A layout that displays a ViewPager with its children that are outside
* the typical pager bounds.
*/
public class PageContainer extends FrameLayout implements ViewPager.OnPageChangeListener {
private ViewPager mPager;
boolean mNeedsRedraw = false;
private Camera mCamera = new Camera();
private int mMaxRotationAngle = 60;
private int mMaxZoom = -120;
public PageContainer(Context context) {
super(context);
init();
}
public PageContainer(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PageContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
//Disable clipping of children so non-selected pages are visible
setClipChildren(false);
//Child clipping doesn't work with hardware acceleration in Android 3.x/4.x
//You need to set this value here if using hardware acceleration in an
// application targeted at these releases.
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
#Override
protected void onFinishInflate() {
try {
mPager = (ViewPager) getChildAt(0);
mPager.setOnPageChangeListener(this);
} catch (Exception e) {
throw new IllegalStateException("The root child of PagerContainer must be a ViewPager");
}
}
public ViewPager getViewPager() {
return mPager;
}
private Point mCenter = new Point();
private Point mInitialTouch = new Point();
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCenter.x = w / 4;
mCenter.y = h / 4;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
//We capture any touches not already handled by the ViewPager
// to implement scrolling from a touch outside the pager bounds.
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mInitialTouch.x = (int)ev.getX();
mInitialTouch.y = (int)ev.getY();
default:
ev.offsetLocation(mCenter.x - mInitialTouch.x, mCenter.y - mInitialTouch.y);
break;
}
return mPager.dispatchTouchEvent(ev);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
//Force the container to redraw on scrolling.
//Without this the outer pages render initially and then stay static
if (mNeedsRedraw) invalidate();
}
#Override
public void onPageSelected(int position) {
View v =this.getViewPager().getChildAt(position);
}
private void transformImageBitmap(View child, Transformation t, int rotationAngle) {
mCamera.save();
final Matrix imageMatrix = t.getMatrix();;
final int imageHeight = child.getLayoutParams().height;;
final int imageWidth = child.getLayoutParams().width;
final int rotation = Math.abs(rotationAngle);
mCamera.translate(0.0f, 0.0f, 100.0f);
if ( rotation < mMaxRotationAngle ) {
float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
mCamera.translate(0.0f, 0.0f, zoomAmount);
}
mCamera.rotateY(rotationAngle);
mCamera.getMatrix(imageMatrix);
imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2));
imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));
mCamera.restore();
}
#Override
public void onPageScrollStateChanged(int state) {
mNeedsRedraw = (state != ViewPager.SCROLL_STATE_IDLE);
}
}
on onPageSelected event I got the view I need to zoom in when selected and zoom out after selecting another item. Please help me out. I added an image to give you an idea what I want.
http://i.stack.imgur.com/xtE89.png