B4A Library [Lib] ScrollView2D

Hello,

Does it need a long explanation ? You can scroll in the two directions.

This lib does not work with Android versions < 2.

v1.01:
I fixed a big bug in the original code.
I added the function SmoothScrollTo.

v1.02:
I restarted from a fresh basis because of the many bugs in the original code. I fixed most of them (now, multitouch events and hardware keys are correctly handled) but a few are left and need more work (sometimes the wrong object get the focus and resizing is not perfectly handled). I noticed by the way that the stock scrollview is bugged and does not set the focus correctly if you move your finger very slowly.
Thanks to Erel, I solved the problem with the B4A documentation.
I added a new function: FullScroll.

v1.03:
I fixed all known bugs (including bugs found in ScrollView & HorizontalScrollView);
I added the scrollbars;
I added three new functions:
- ScrollbarsVisibility
- FadingEdges
- GiveFocusToFirstVisible.

v1.1:
I fixed a problem with events that were not fired if declared in a class;
I added two functions: ScrollingIsFinished and DisableTouchEventInterception.

v1.2:
SV2D appears now as a custom view in the designer with all its properties.

v1.3:
I fixed a bug (SV_2 = SV_1 did not work because the inner panel was declared in the wrong class).

Enjoy,
Fred
 

Attachments

  • ScrollView2D v1.3.zip
    120.5 KB · Views: 5,478
  • Java source - ScrollView2D.zip
    17.6 KB · Views: 1,551
Last edited:

mc73

Well-Known Member
Licensed User
Longtime User
Fails on my Samsung Galaxy S. It just hangs. Perhaps it has to do with my os version? 2.2.2. rooted.
 

derez

Expert
Licensed User
Longtime User
Great library !
Can you please change the args in some of the methods to names which describe the use of the argument ? (like in setlayout, setbackground image)
 

Informatix

Expert
Licensed User
Longtime User
Can you please change the args in some of the methods to names which describe the use of the argument ? (like in setlayout, setbackground image)
I'd like to change them but I don't know how to do that (without redeclaring everything). I suppose I have to add something to tell to B4A to add the View object documentation to my ScrollView documentation, but I don't know what. Erel ? :sign0085:
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Add this class to your code:
B4X:
package anywheresoftware.b4a.objects;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.Button;
import anywheresoftware.b4a.AbsObjectWrapper;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BALayout;
import anywheresoftware.b4a.ObjectWrapper;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.Hide;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BALayout.LayoutParams;
import anywheresoftware.b4a.keywords.Common;
import anywheresoftware.b4a.objects.drawable.ColorDrawable;
import anywheresoftware.b4a.objects.drawable.CanvasWrapper.BitmapWrapper;
import anywheresoftware.b4a.objects.drawable.ColorDrawable.GradientDrawableWithCorners;

@Hide
@Events(values={"Click", "LongClick"})
public class ViewWrapper<T extends View> extends AbsObjectWrapper<T>{
   protected BA ba;
   @Hide
   public static int lastId;

   public void Initialize(final BA ba, String EventName) {
      innerInitialize(ba, EventName.toLowerCase(BA.cul), false);
   }
   @Hide
   public void innerInitialize(final BA ba, final String eventName, boolean keepOldObject) {
      this.ba = ba;
      getObject().setId(++lastId);
      if (ba.subExists(eventName + "_click")) {

         getObject().setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
               ba.raiseEvent(ViewWrapper.this.getObject(), eventName + "_click");
            }

         });
      }
      if (ba.subExists(eventName + "_longclick")) {
         getObject().setOnLongClickListener(new View.OnLongClickListener() {

            @Override
            public boolean onLongClick(View v) {
               ba.raiseEvent(ViewWrapper.this.getObject(), eventName + "_longclick");
               return true;
            }

         });
      }
      
   }
   /**
    * Gets or sets the background drawable.
    */
   public Drawable getBackground() {
      return getObject().getBackground();
   }
   public void setBackground(Drawable drawable) {
      getObject().setBackgroundDrawable(drawable);
   }
   public void SetBackgroundImage(Bitmap Bitmap) {
      anywheresoftware.b4a.objects.drawable.BitmapDrawable bd = new anywheresoftware.b4a.objects.drawable.BitmapDrawable();
      bd.Initialize(Bitmap);
      getObject().setBackgroundDrawable(bd.getObject());
   }
   /**
    * Invalidates the whole view forcing the view to redraw itself.
    *Redrawing will only happen when the program can process messages. Usually when it finishes running the current code. 
    */
   public void Invalidate() {
      getObject().invalidate();
   }
   /**
    * Invalidates the given rectangle.
    *Redrawing will only happen when the program can process messages. Usually when it finishes running the current code. 
    */
   public void Invalidate2(Rect Rect) {
      getObject().invalidate(Rect);
   }
   /**
    * Invalidates the given rectangle.
    *Redrawing will only happen when the program can process messages. Usually when it finishes running the current code. 
    */
   public void Invalidate3(int Left, int Top, int Right, int Bottom) {
      getObject().invalidate(Left, Top, Right, Bottom);
   }
   /**
    * Gets or sets the view's width.
    */
   public void setWidth(int width) {
      ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getObject().getLayoutParams();
      lp.width = width;
      getObject().getParent().requestLayout();
   }
   public int getWidth() {
      return ((ViewGroup.LayoutParams)getObject().getLayoutParams()).width;
   }
   public int getHeight() {
      return ((ViewGroup.LayoutParams)getObject().getLayoutParams()).height;

   }
   public int getLeft() {
      BALayout.LayoutParams lp = (LayoutParams) getObject().getLayoutParams();
      return lp.left;
   }
   public int getTop() {
      BALayout.LayoutParams lp = (LayoutParams) getObject().getLayoutParams();
      return lp.top;
   }
   public void setHeight(int height) {
      ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) getObject().getLayoutParams();
      lp.height = height;
      getObject().getParent().requestLayout();
   }

   public void setLeft(int left) {
      BALayout.LayoutParams lp = (LayoutParams) getObject().getLayoutParams();
      lp.left = left;
      getObject().getParent().requestLayout();
   }

   public void setTop(int top) {
      BALayout.LayoutParams lp = (LayoutParams) getObject().getLayoutParams();
      lp.top = top;
      getObject().getParent().requestLayout();
   }
   /**
    * Sets the background of the view to be a ColorDrawable with the given color.
    *If the current background is of type GradientDrawable or ColorDrawable the round corners will be kept.
    */
   public void setColor(int color) {
      Drawable d = getObject().getBackground();
      if (d != null && d instanceof GradientDrawable) {
         float radius = 0;
         if (d instanceof GradientDrawableWithCorners) {
            radius = ((GradientDrawableWithCorners)d).cornerRadius;
         }
         else {
            GradientDrawable g = (GradientDrawable) getObject().getBackground();
            try {
               Field state = g.getClass().getDeclaredField("mGradientState");
               state.setAccessible(true);
               Object gstate = state.get(g);
               Field radiusF = gstate.getClass().getDeclaredField("mRadius");
               radius = (Float) radiusF.get(gstate);
               
            } catch (Exception e) {
               Common.Log(e.toString());
            }
         }
         ColorDrawable cd = new ColorDrawable();
         cd.Initialize(color, (int)radius);
         getObject().setBackgroundDrawable(cd.getObject());
      }
      else {
         getObject().setBackgroundColor(color);
      }

   }
   public void setTag(Object tag) {
      getObject().setTag(tag);
   }
   /**
    * Gets or sets the Tag value. This is a place holder which can used to store additional data.
    */
   public Object getTag() {
      return getObject().getTag();
   }
   public void setVisible(boolean Visible) {
      getObject().setVisibility(Visible ? View.VISIBLE : View.GONE);
   }
   public boolean getVisible() {
      return getObject().getVisibility() == View.VISIBLE ? true : false;
   }
   public void setEnabled(boolean Enabled) {
      getObject().setEnabled(Enabled);
   }
   public boolean getEnabled() {
      return getObject().isEnabled();
   }
   /**
    * Changes the Z order of this view and brings it to the front.
    */
   public void BringToFront() {
      if (getObject().getParent() instanceof ViewGroup) {
         ViewGroup vg = (ViewGroup) getObject().getParent();
         vg.removeView(getObject());
         vg.addView(getObject());
      }
   }
   /**
    * Changes the Z order of this view and sends it to the back.
    */
   public void SendToBack() {
      if (getObject().getParent() instanceof ViewGroup) {
         ViewGroup vg = (ViewGroup) getObject().getParent();
         vg.removeView(getObject());
         vg.addView(getObject(), 0);
      }
   }
   /**
    * Removes this view from its parent.
    */
   public void RemoveView() {
      if (getObject().getParent() instanceof ViewGroup) {
         ViewGroup vg = (ViewGroup) getObject().getParent();
         vg.removeView(getObject());
      }
   }
   /**
    * Changes the view position and size.
    */
   public void SetLayout(int Left, int Top, int Width, int Height) {
      BALayout.LayoutParams lp = (LayoutParams) getObject().getLayoutParams();
      lp.left = Left;
      lp.top = Top;
      lp.width = Width;
      lp.height = Height;
      getObject().getParent().requestLayout();
   }
   /**
    * Tries to set the focus to this view.
    *Returns True if the focus was set.
    */
   public boolean RequestFocus() {
      return getObject().requestFocus();
   }
}
 

moster67

Expert
Licensed User
Longtime User
Very nice library!

Tested on my HTC HD2 (Gingerbread) and Acer Iconia TAB A500 (ICS 4.03).

Nice picture of your son too.

:sign0098:
 

mc73

Well-Known Member
Licensed User
Longtime User
Does it hang when it starts ? When you scroll ?
Try to remove the picture (the LoadBitmap line). Does it work now ?

Your version is not the problem. The library has been compiled with API 7 and Froyo is built upon API 8.
I really don't know. It just hangs even if I remove the picture.
 

mc73

Well-Known Member
Licensed User
Longtime User
Check the unfiltered logs and see if there is any related message.
Yes, there is an uncaught exception with onscrollchanged event.
B4X:
>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
CheckJNI is OFF
creating instr width table
--- registering native functions ---
Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=flm.scrollview2d.demo/.main }
onPause()
Shutting down VM
adbd disconnected
WallpaperManager setVisibility visible true
Start proc flm.scrollview2d.demo for activity flm.scrollview2d.demo/.main: pid=3282 uid=10080 gids={}
WorkspaceDraw: Workspace drawWallpaperImage()
Converting to boolean: TypedValue{t=0x3/d=0x593d "res/anim/accelerate_decelerate_interpolator.xml" a=1 r=0x10a0004}


Converting to boolean: TypedValue{t=0x3/d=0x593d "res/anim/accelerate_decelerate_interpolator.xml" a=1 r=0x10a0004}
Could not find method java.lang.String.<init>, referenced from method anywheresoftware.b4a.BA$1.uncaughtException


VFY: unable to resolve direct method 1829: Ljava/lang/String;.<init> ([BLjava/nio/charset/Charset;)V
VFY: replacing opcode 0x70 at 0x0033
VFY: dead code 0x0036-003e in Lanywheresoftware/b4a/BA$1;.uncaughtException (Ljava/lang/Thread;Ljava/lang/Throwable;)V


** Activity (main) Create, isFirst = true **


Could not find method anywheresoftware.b4a.BA.raiseEventFromUI, referenced from method flm.b4a.scrollview2d.ScrollView2DWrapper$MyScrollView.onScrollChanged


VFY: unable to resolve virtual method 566: Lanywheresoftware/b4a/BA;.raiseEventFromUI (Ljava/lang/Object;Ljava/lang/String;[Ljava/lang/Object;)V
VFY: replacing opcode 0x6e at 0x002f


wallpaper stop


** Activity (main) Resume **


Displayed activity flm.scrollview2d.demo/.main: 396 ms (total 396 ms)


onWindowFocusChanged(false)


ACTION_BATTERY_CHANGED pluggedType: 2


ACTION_BATTERY_CHANGED pluggedType: 2


Event [ SCAN-RESULTS ]


WPS-AP-AVAILABLE 


No suitable AP found.
CTRL-EVENT-NO-CONNECTION
Event [WPS-AP-AVAILABLE ]
Event [CTRL-EVENT-NO-CONNECTION]
action: android.net.wifi.SHOW_AP_LIST_DIALOG


showApDialog
isShowingAccessPointListDialog():false


setShowAccessPointListDialog():false
ACTION_BATTERY_CHANGED pluggedType: 2


ACTION_BATTERY_CHANGED pluggedType: 2


ACTION_BATTERY_CHANGED pluggedType: 2


ID[0]=0(1) Dn(0=>1)


Ulight 3->7|0


Dsptch > Window{482f0660 flm.scrollview2d.demo/flm.scrollview2d.demo.main paused=false}
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
 

mc73

Well-Known Member
Licensed User
Longtime User
Which version of Basic4android are you using? Make sure that there are no old copied of internal libraries in the additional libraries path.
Using 1.90 and avoiding to update libs at this particular point, since I have to make sure that the app I gave to my clients, runs stably, since this is my very first app at their field. I'm taking a close look to all updated libs, and of course b4a's new version, in order to feel more 'secure' about re-interpreting my app. I hope you understand me, Erel. Clients here are a bit aggressive :D
 

mc73

Well-Known Member
Licensed User
Longtime User
This library requires v2.00.
I am using a webView for such procedures, thus, I guess I can wait a while :)
By the way, my current libs' version are:
core 1.90
dialogs 2.80
http 1.20
jsinterface 1.30
network 1.11
phone 1.80
randomaccessfile 1.30
sql 1.02
webviewextras 1.10

Any way to make the update procedure simple or I just have to browse each library and check for an update? Just asking.
 
Top