I have a list, it captured moving finger, and you can delete an item by sliding your finger
if the image is not loaded in my container, with ImageView.setImage(), the container moves correctly.
However, if I loaded one image the container moves slowler.
Why is this happening?
Attach images below.
1.moves correctly
not moves correctly
always moves the container from left to rigth
Why is it?
Thanks.
UPDATE 19/01/2014
i reduced bitmap to 150 kb and continue equal.
leave my code
objelementos.lnyDatosCliente.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, final MotionEvent event) {
final CCliente objcCCliente = lstLista.get(objelementos.posicion);
CAnimaciones objAnmanim = new CAnimaciones();
Display pantalla = afrmGstionClientes.getActivity().getWindowManager().getDefaultDisplay();
final int ancho = pantalla.getWidth();
switch ( event.getAction()) {
case MotionEvent.ACTION_DOWN:
fdYPrimeroPulsado = event.getRawY();
fdXPulsadoInicio = event.getRawX();
fdXUltimaPulsado = event.getRawX();
iTamanioLnyPulsado =0;
break;
case MotionEvent.ACTION_MOVE:
float fdXPulsado = event.getRawX();
float fdXMovimiento = fdXPulsado- fdXUltimaPulsado;
objelementos.lnyDatosCliente.setVisibility(4);
objelementos.lnyDatosClienteToMove.setVisibility(0);
objelementos.lnyDatosClienteToMove.setX(fdXMovimiento);
iTamanioLnyPulsado =1;
break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL:
float fdXPulsad = event.getRawX();
float xmov =fdXPulsad- fdXUltimaPulsado;
fdYUltimoPulsado = event.getRawY();
int difx = (int)fdXPulsad- (int)fdXPulsadoInicio;
if (difx>120){
ObjectAnimator animaciion = objAnmanim.CrearAnimacion(objelementos.lnyDatosClienteToMove, xmov, ancho+10, "x", 85);//(xFin-20, ancho+10, 200) ;
animaciion.start();
new Handler().postDelayed(new Runnable() {
public void run() {
float num = objcCCliente.getposicionXInicio();
AlertDialog.Builder builder = new AlertDialog.Builder(
getContext());
builder.setIcon(R.drawable.ic_launcher);
builder.setTitle("!AVISO!");
builder.setMessage("¿Estas seguro de eliminar el cliente?")
.setPositiveButton("Si", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
CustomAdapterListadoClientes.this.lstLista.remove(objelementos.posicion);
CustomAdapterListadoClientes.this.notifyDataSetChanged();
dialog.dismiss();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
vol(ancho-10, objelementos.lnyDatosCliente.getX(), objelementos.lnyDatosClienteToMove, 180, objelementos.lnyDatosCliente);
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
}, animaciion.getDuration());
}else{
if (iTamanioLnyPulsado==0){
float dify = fdYPrimeroPulsado -fdYUltimoPulsado;
if (dify<0){
dify*=-1;
}
if (dify<10){
float fddondeesta = objelementos.lnyDatosCliente.getY();
ObjectAnimator animaciion = objAnmanim.CrearAnimacion(objelementos.lnyDatosCliente, fddondeesta-1, fddondeesta, "x",50);
animaciion.start();
Cnavegar objNavegar = new Cnavegar();
AfrmHigthModificationCliente afrmModificacion = new AfrmHigthModificationCliente(true, objcCCliente,afrmGstionClientes);
objNavegar.RemplazarFragmento(R.id.rtlAltas, afrmModificacion, "AfrmHigthModificationCliente", afrmGstionClientes.getActivity().getSupportFragmentManager());
}
}else{
if (difx>0){
vol(xmov, objelementos.lnyDatosCliente.getX(), objelementos.lnyDatosClienteToMove, 180, objelementos.lnyDatosCliente);
}else{
vol(xmov, objelementos.lnyDatosCliente.getX(), objelementos.lnyDatosClienteToMove, 180, objelementos.lnyDatosCliente);
}
}
}
break;
}
return true;
}
});
Are you using ViewHolder pattern?
Are you loading your images on another thread?
For load images I use Picasso library.
solve my problem of slow , which resided not in the size of the image
I used two linear layout changing your visibility associated with this adapter to change it to visible or invisiblo gone.
he adapter had to rewrite the code again and has this was because my problem.
now only work with linerar layout unchanged visibility, position and only my application I run to perfection
thanks for your help everyone
Related
I'm new to building apps on Android. I do have Java and android studio working experience, and build basic android apps but the project I'm working on now is a little bit complicated.
I want to move a image inside a imageview corresponding to touch pointer, in other words to direction of touch but inside a specific area(circular).
Just like in android app pou i.e. pou eyes move corresponding to touch pointer.
I started with below code:
public class TouchActivity extends Activity {
private ViewGroup mainLayout;
private ImageView image;
private int xDelta;
private int yDelta;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_touch);
mainLayout = (RelativeLayout) findViewById(R.id.main);
image = (ImageView) findViewById(R.id.image);
image.setOnTouchListener(onTouchListener());
}
private OnTouchListener onTouchListener() {
return new OnTouchListener() {
#SuppressLint("ClickableViewAccessibility")
#Override
public boolean onTouch(View view, MotionEvent event) {
final int x = (int) event.getRawX();
final int y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams)
view.getLayoutParams();
xDelta = x - lParams.leftMargin;
yDelta = y - lParams.topMargin;
break;
case MotionEvent.ACTION_UP:
Toast.makeText(TouchActivity.this,
"thanks for new location!", Toast.LENGTH_SHORT)
.show();
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view
.getLayoutParams();
layoutParams.leftMargin = x - xDelta;
layoutParams.topMargin = y - yDelta;
layoutParams.rightMargin = 0;
layoutParams.bottomMargin = 0;
view.setLayoutParams(layoutParams);
break;
}
mainLayout.invalidate();
return true;
}
};
}
}
... and successfully managed to move an image corresponding to touch pointer but I want to implement something like this:
(eyes are moving according to touch but inside a specific area)
Any ideas?
(by kalu) Move click image inside imageview ajust height or with depends the size of resource(image) and translate x or y direction.
Try This:
// your image view
ImageView mCoverView = findViewById(R.id.imageview);
Glide.with(aActivity).load(cover) //set img url
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(new BitmapImageViewTarget(mCoverView) {
#Override
protected void setResource(Bitmap resource) {
final Bitmap f_res = resource;
// just if you want change for a drawable res
// final Bitmap f_res = BitmapFactory.decodeResource(aActivity.getResources(),R.drawable.ic_ampliada);
//k ajust center but ajust height or with depend the image
mCoverView.setScaleType(ImageView.ScaleType.CENTER_CROP);
mCoverView.setImageBitmap(f_res);
final String dir;
if(f_res.getWidth()>f_res.getHeight())
dir="x";
else
dir="y";
mCoverView.setOnClickListener(new View.OnClickListener() {
// size of move
int value = 25;
double resh=f_res.getHeight();
double resw=f_res.getWidth();
double coverh =mCoverView.getHeight();
double coverw = mCoverView.getWidth();
int xTranslate = 0;
double sacale_w_from_h = coverh / resh * resw;
//k wtotal distancia do centro as bordas (x=0 (centro imagem))
double wtotal = (sacale_w_from_h/2);
int yTranslate = 0;
double sacale_h_from_w = coverw / resw * resh;
//k wtotal distancia do centro as bordas (y=0 (centro imagem))
double htotal = sacale_h_from_w / 2;
#Override
public void onClick(View v) {
if (dir == "x"){
if (xTranslate>wtotal || xTranslate<-wtotal)
value=-value;
xTranslate += value;
}else if(dir == "y"){
if (yTranslate>htotal || yTranslate<-htotal)
value=-value;
yTranslate += value;
}
this.translateImage(xTranslate,yTranslate);
}
private void translateImage(int xTranslate, int yTranslate)
{
Bitmap translateBitmap = Bitmap.createBitmap(f_res.getWidth() + xTranslate, f_res.getHeight() + yTranslate, f_res.getConfig());
Canvas translateCanvas = new Canvas(translateBitmap);
Matrix translateMatrix = new Matrix();
translateMatrix.setTranslate(xTranslate, yTranslate);
Paint paint = new Paint();
translateCanvas.drawBitmap(f_res, translateMatrix, paint);
mCoverView.setImageBitmap(translateBitmap);
}
});
}
#Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
});
//-------------------------------------------------------------------
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.
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));
}
}
I want to drag a view. Until now i tried it with a LinearLayout and margins and with a AbsoluteLayout.
AbsoluteLayout example:
button.Touch = (clickedView, motionEvent) =>
{
Button b = (Button)clickedView;
if (motionEvent.Action == MotionEventActions.Move)
{
AbsoluteLayout.LayoutParams layoutParams = new AbsoluteLayout.LayoutParams(100, 35, (int)motionEvent.GetX(), (int)motionEvent.GetY());
b.LayoutParameters = layoutParams;
}
return true;
};
In every case I tried I got a curios behaviour. Here's why. The view i'm dragging follows my finger but jumps always between two positions. One postition hits my finger the other is somewhere to my fingers left-top. If I'm just writing my current position into a textview (without moving the view) the coordinates behave as expected. But if i'm also moving the view they are jumping again.
How can i avoid this?
EDIT: I used sounds comment on my question to implement a working draging for monodroid (it is done for Java/Android SDK in the linked site). Maybe others are interested in doing that some day, so here's my solution:
[Activity(Label = "Draging", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
private View selectedItem = null;
private int offset_x = 0;
private int offset_y = 0;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
ViewGroup vg = (ViewGroup)FindViewById(Resource.Id.vg);
vg.Touch = (element, motionEvent) =>
{
switch (motionEvent.Action)
{
case MotionEventActions.Move:
int x = (int)motionEvent.GetX() - offset_x;
int y = (int)motionEvent.GetY() - offset_y;
int w = WindowManager.DefaultDisplay.Width - 100;
int h = WindowManager.DefaultDisplay.Height - 100;
if (x > w)
x = w;
if (y > h)
y = h;
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
new ViewGroup.MarginLayoutParams(
LinearLayout.LayoutParams.WrapContent,
LinearLayout.LayoutParams.WrapContent));
lp.SetMargins(x, y, 0, 0);
selectedItem.LayoutParameters = lp;
break;
default:
break;
}
return true;
};
ImageView img = FindViewById<ImageView>(Resource.Id.img);
img.Touch = (element, motionEvent) =>
{
switch (motionEvent.Action)
{
case MotionEventActions.Down:
offset_x = (int)motionEvent.GetX();
offset_y = (int)motionEvent.GetY();
selectedItem = element;
break;
default:
break;
}
return false;
};
}
}
I searched all over, but could not find a solution.
I have a view (lets call it myView) inside a scrollview. myView is bigger than the screen. Since I'm able to get the relative x,y position of my finger inside myView, I would like to make the scrollView autoscroll to the top/bottom when my finger enters a certain top/bottom threshold.
I have some ideas, namely translating the drag location to the screen position but this did not solve this problem.
thanks in advance
cheers
All right I figured it out by myself.
First I had to extend the ScrollView class and added an interface OnScrollViewListener.
public class MyScrollView extends ScrollView {
private OnScrollViewListener mListener;
public MyScrollView(Context c, AttributeSet attrs) {
super(c, attrs);
}
#Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (mListener != null) {
mListener.onScrollChanged((OnScrollViewListener) this);
}
}
public void setOnScrollViewListener(OnScrollViewListener listener) {
mListener = listener;
}
public static interface OnScrollViewListener {
public void onScrollChanged(OnScrollViewListener listener);
}
}
Next in my Activity I inserted a member mScrollDistance that indicates the amount of
pixels the user scrolls.
public class ScrollActivity extends Activity {
private int mScrollDistance;
#Override
protected void OnCreate(...) {
...
final MyScrollView myScrollView = (MyScrollView) findViewById(R.id.scroll_view);
myScrollView.setOnScrollViewListener(new MyScrollView.OnScrollViewListener() {
public void onScrollChanged(OnScrollViewListener listener) {
mScrollDistance = listener.getScrollY();
}
}
// making an drag and drop in an view that is inside the MyScrollView
final LinearLayout myLayout = (LinearLayout)findViewById(R.id.linear_layout);
myLayout.setOnDragListener(new View.OnDragListener() {
public boolean onDrag (View v, DragEvent event) {
int action = event.getAction();
switch(action) {
case DragEvent.ACTION_DRAG_STARTED: {
}
case DragEvent.ACTION_DRAG_LOCATION: {
int y = Math.round(event.getY());
int translatedY = y - mScrollDistance;
int threshold = 50;
// make a scrolling up due the y has passed the threshold
if (translatedY < threshold) {
// make a scroll up by 30 px
myScrollView.scrollBy(0, -30);
}
// make a autoscrolling down due y has passed the 500 px border
if (translatedY + threshold > 500) {
// make a scroll down by 30 px
myScrollView.scrollBy(0, 30);
}
// listen for more actions here
// ...
}
}
}
}
Now, mScrollDistance gets always a new value and the drag location will be translated to the view location.
I tested this and it works on layouts/views that are bigger than the screen size.
Hope that helps.
I came up with a different solution and I am happy with it.
I want to be able to drag and drop views inside a ScrollView. The ScrollView then needs to scroll up and down automatically when the shadow reaches the edges of the scroll view.
I ended up with a solution that detects wether the drop zone is completely visible inside the scrollview (with a 100px margin) and adjust the scroll view otherwise.
#Override
public boolean onDrag(View view, DragEvent event) {
MainWidget dropZoneView = (MainWidget) view;
int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
//(... other stuff happens here)
case DragEvent.ACTION_DRAG_LOCATION:
ScrollView mainScrollView = (ScrollView) findViewById(R.id.main_scroll);
int topOfDropZone = dropZoneView.getTop();
int bottomOfDropZone = dropZoneView.getBottom();
int scrollY = mainScrollView.getScrollY();
int scrollViewHeight = mainScrollView.getMeasuredHeight();
Log.d(LOG_TAG,"location: Scroll Y: "+ scrollY + " Scroll Y+Height: "+(scrollY + scrollViewHeight));
Log.d(LOG_TAG," top: "+ topOfDropZone +" bottom: "+bottomOfDropZone);
if (bottomOfDropZone > (scrollY + scrollViewHeight - 100))
mainScrollView.smoothScrollBy(0, 30);
if (topOfDropZone < (scrollY + 100))
mainScrollView.smoothScrollBy(0, -30);
break;
default:
break;
}
return true;
}
Hope this helps!
I used a timer in In C#
ScrollCalendar ScrollCalendar = new ScrollCalendar (yourScrollView);
Inside the drag event
public bool OnDrag (View v, DragEvent e)
{
var dragshadow = new EventDateDragShadow (v);
switch (e.Action) {
case DragAction.Started:
return true;
case DragAction.Entered:
break;
case Android.Views.DragAction.Location:
if (e.GetY () < 90) {
ScrollCalendar.StartScroll (-15);
} else if (e.GetY () > yourScrollView.Height - 90) {
ScrollCalendar.StartScroll (15);
} else
ScrollCalendar.StopScroll ();
return (true);
case DragAction.Exited:
return true;
case DragAction.Drop:
return true;
case DragAction.Ended:
ScrollCalendar.StopScroll ();
v.SetOnDragListener (null);
return true;
}
return true;
}
The ScrollCalendar class
public class ScrollCalendar
{
private ScrollView Calendar;
private System.Timers.Timer Timer;
private int ScrollDistance;
public ScrollCalendar(ScrollView calendar)
{
Calendar = calendar;
Timer = new System.Timers.Timer();
Timer.Elapsed+=new ElapsedEventHandler(Scroll);
Timer.Interval = 50;
}
public void StartScroll(int scrollDistance)
{
if (Timer.Enabled) {
return;
}
ScrollDistance = scrollDistance;
Timer.Enabled = true;
}
public void StopScroll()
{
Timer.Enabled = false;
}
private void Scroll(object source, ElapsedEventArgs e)
{
Calendar.SmoothScrollBy (0, ScrollDistance);
}
}
Change the StartScroll value and the Timer.Interval to adjust the speed of the scroll.
I have modified answer of Tiago A.
I faced the same problem and the solution from Tiago A was small and easy but have some limitation so if others require this may help.
Thanks to Tiago A.
case DragEvent.ACTION_DRAG_LOCATION:
ScrollView myScrollView =findViewById(R.id.myScrollView);
int topOfDropZone = myScrollView.getChildAt(0).getTop();
int bottomOfDropZone = myScrollView.getChildAt(0).getBottom();
int scrollY = myScrollView.getScrollY();
int scrollViewHeight = myScrollView.getMeasuredHeight();
if (Math.round(event.getY()) > scrollViewHeight - (scrollViewHeight / 45))
if (bottomOfDropZone > (scrollY + scrollViewHeight - 100))
myScrollView.smoothScrollBy(0, 30);
if (Math.round(event.getY()) < (scrollViewHeight / 45))
if (topOfDropZone < (scrollY + 100))
myScrollView.smoothScrollBy(0, -30);
return true;