Android Tutorial ScrollView example

The ScrollView is a very useful container which allows you to show many other views on a small screen.
The ScrollView holds an inner panel view which actually contains the other views.
The user vertically scrolls the inner panel as needed.

In this example we will load images from the sdcard and add those to a ScrollView.

scrollview1.png


Adding views to a ScrollView is done by calling:
B4X:
ScrollView.Panel.AddView(...)
In order to avoid "out of memory" errors we use LoadBitmapSample instead of LoadBitmap. LoadBitmapSample accepts two additional parameters: MaxWidth and MaxHeight. When it loads a bitmap it will first get the bitmap original dimensions and then if the bitmap width or height are larger than MaxWidth or MaxHeight the bitmap will be subsampled accordingly. This means that the loaded bitmaps will have lower resolution than the original bitmap. The width / height ratio is preserved.

The following code sets the inner panel height and adds an ImageView for each loaded bitmap:
B4X:
    ScrollView1.Panel.Height = 200dip * Bitmaps.Size 'Set the inner panel height according to the number of images.
    For i = 0 To Bitmaps.Size - 1
        Dim iv As ImageView 'create an ImageView for each bitmap
        iv.Initialize("") 'not interested in any events so we pass empty string.
        Dim bd As BitmapDrawable
        bd.Initialize(Bitmaps.Get(i))
        iv.Background = bd 'set the background of the image view.
        'add the image view to the scroll bar internal panel.
        ScrollView1.Panel.AddView(iv, 5dip, 5dip + i * 200dip, ScrollView1.Width - 10dip, 190dip)
    Next
The code that is loading the bitmaps looks for jpg files under /sdcard/Images

If you want to run this program on the emulator you will first need to create this folder and copy some images to it.
This is done with the "adb" command, that comes with Android SDK.
Open a shell console (Windows Start - Run - Cmd).
Go to the sdk tools folder and issue:
B4X:
c:\android-sdk-windows\tools> adb -e shell mkdir /sdcard/Images
The -e parameter tells adb to send the command to the only connected emulator.
The command is mkdir with the name of the folder.
Note that Android file system is case sensitive.

Now we need to copy some images to this folder.
This is done with the push command:
B4X:
adb -e push "C:\temp" /sdcard/Images
This will copy all files under c:\temp to the Images folder.

The emulator is very slow compared to a real device. While on a real device 50 large images load in 2-3 seconds. It can take a long time for the emulator to load a few small images. I recommend you to copy 2 - 3 small images at most.

Also the experience of the ScrollView on the emulator cannot be compared to a real device (with capacitive screen).

The program is available here: http://www.b4x.com/android/files/tutorials/ScrollView.zip
 

johnaaronrose

Active Member
Licensed User
Longtime User
From existing scrolling text in Label, displaying text occupying all of screen

Sorry but I don't really understand what exactly you want to do.

Do you have a screen where you display information and from there you want to display details, the long text or images on other screens?
Do you have an example ?

It would be better to start a new thread for this question because it's not really related to the title of this thread.

Best regards.


Yes to above question. Please see thread entitled "From existing scrolling text in Label, displaying text occupying all of screen".
 

johnaaronrose

Active Member
Licensed User
Longtime User
ScrollView.Panel.Height set equal to Label.Top + Label.Height

Not really.
The real Label.Height is defined by the Label.Width and the text displayed in it.
Then yo must set the ScrollView.Panel.Height equal to the Label.Top + Label.Height.
You need to include Label.Top if it's not equal to 0.
You could also add a small margin for the bottom.

You need to declare StrUtil in Globals:
B4X:
Dim StrUtil As StringUtils
Best regards.

I've been trying to understand why "set the ScrollView.Panel.Height equal to the Label.Top + Label.Height. ".

I've now done this and it gives problems: see below. I have a ScrollInformation view which contains, in its Panel, a Label Information view (in which there is text that I want to be vertically scrollable). Directly above the ScrollInformation view is a LabelCountry view. Directly below the ScrollInformation view is a ImageViewPhoto view. So, I do not want the ScrollInformation view to interfere with / be interfered by the LabelCountry & ImageViewPhoto views.

My views' L,T,W,H values for a particular piece of text are:
LabelCountry(0,90,160,30)
ScrollViewInformation(0,120,210,200)
LabelInformation(0,120,210,1188)
ImageViewPhoto(0,324,210,155)

The ScrollViewInformation.Panel is Width 210 & Height 1308.

What happens is that the text starts about the same distance down ScrollViewInformation as LabelInformation.Top. Also, it scrolls down not to the bottom of the text but approx LabelInformation.Top from the bottom of the text. I have tried both setting ScrollViewInformation.Panel.ScrollPosition to 0 & to Label.Top, but it makes no difference to the display. Any ideas?
 

johnaaronrose

Active Member
Licensed User
Longtime User
Questions

I think the attached example is what you are looking for.

Best regards.

I've looked at the example which works OK when I ran it. I've modified my app but still have the same problem.

Some questions:
1. Is it allowable for the ScrollViewInformation.Panel to be the same size & position as ScrollViewInformation.Panel?
2. When coding ScrollViewInformation.Panel.AddView(LabelInformation..., should the Left & Top be relative to ScrollViewInformation.Panel Left & Top?
3. What value should ScrollViewInformation.ScrollPosition be set to in order to position the text at its start?
 
Last edited:

klaus

Expert
Licensed User
Longtime User
I've modified my app but still have the same problem.
Without seeing your code impossible to give you any advice.

1. Sorry I don't understand ?
The ScrollViewInformation.Panel has the same width as ScrollViewInformation and you can set ScrollViewInformation.Panel.Height the value you want.
2. Yes
If you set ScrollViewInformation.Panel.AddView(LabelInformation, 10dip, 10dip, 150dip, 50dip) the top and left postions of LabelInformation are 10dip right and 10dip below the ScrollViewInformation.Panel upper left corner.
3. 0 (zero)

Best regards.
 

johnaaronrose

Active Member
Licensed User
Longtime User
Test app

Klaus,

I've attached my app (with irrelevant coding, activities, layouts etc) removed. There are 3 files attached:
Test.zip - app containing source, files, .apk etc
TestLog.txt - Log of a run using 320x480 emulator
TestModules.zip - containing DBUtils & HttpUtils2
As well as Core, app uses libraries: HTTP, MLfiles, ScrollView2D, SQL & StringUtils

The app has 2 Activities: main used to download the database from the web & view to view the resultant data: Test app is coded to only read 2 rows from the database. I've also attached the text (in the lblInformation view) for the first row displayed.
View attachment Test.zip

View attachment TestLog.txt

View attachment TestModules.zip

View attachment TestlblInformation.txt

PS I also made a change to MLfiles to make the filename variable Public as otherwise there's a compile error.

Thanks for offering to look at the code to find the reason why the lblInformation view does not display & scroll properly.
 

klaus

Expert
Licensed User
Longtime User
Here you are.
It took me a while to find out where the problem was.
In Activity_Resume you changed the layout of the label to wrong values ?!
The two DoEvents are necessary to update the scroll positions.
B4X:
Sub Activity_Resume
'    ResizeViews
'    lblInformation.SetLayout(scvInformation.Left, scvInformation.Top, scvInformation.Width, scvInformation.Height)
    scvInformation.ScrollPosition = scvInformationScrollPosition
'    sv2dPhoto.Panel.Width = ivPhoto.Width
'    sv2dPhoto.Panel.Height = ivPhoto.Height
    sv2dPhoto.HorizontalScrollPosition = sv2dPhotoHorizontalScrollPosition
    DoEvents
    sv2dPhoto.VerticalScrollPosition = sv2dPhotoVerticalScrollPosition
    DoEvents
End Sub
You must also move these variables from Globals to Process_Globals otherwise the values are lost.
B4X:
  Dim scvInformationScrollPosition As Int
     scvInformationScrollPosition = 0
   Dim sv2dPhotoHorizontalScrollPosition As Int
     sv2dPhotoHorizontalScrollPosition = 0
   Dim sv2dPhotoVerticalScrollPosition As Int
     sv2dPhotoVerticalScrollPosition = 0
Best regards.
 

Attachments

  • TestNew.zip
    18.5 KB · Views: 565

johnaaronrose

Active Member
Licensed User
Longtime User
Changing scvInformation position & size

Here you are.
It took me a while to find out where the problem was.
In Activity_Resume you changed the layout of the label to wrong values ?!
The two DoEvents are necessary to update the scroll positions.
B4X:
Sub Activity_Resume
'    ResizeViews
'    lblInformation.SetLayout(0, 0, scvInformation.Width, scvInformation.Height)
    scvInformation.ScrollPosition = scvInformationScrollPosition
'    sv2dPhoto.Panel.Width = ivPhoto.Width
'    sv2dPhoto.Panel.Height = ivPhoto.Height
    sv2dPhoto.HorizontalScrollPosition = sv2dPhotoHorizontalScrollPosition
    DoEvents
    sv2dPhoto.VerticalScrollPosition = sv2dPhotoVerticalScrollPosition
    DoEvents
End Sub
You must also move these variables from Globals to Process_Globals otherwise the values are lost.
B4X:
  Dim scvInformationScrollPosition As Int
     scvInformationScrollPosition = 0
   Dim sv2dPhotoHorizontalScrollPosition As Int
     sv2dPhotoHorizontalScrollPosition = 0
   Dim sv2dPhotoVerticalScrollPosition As Int
     sv2dPhotoVerticalScrollPosition = 0
Best regards.

I checked your TestNew out & it was OK on my system. I've changed my app so that the variables defining ScrollPosition for scvInformationScroll & sv2DPhoto are now Private in Process_Globals and they are OK. Also, I've used DoEvents after changing properties for scvInformation, scvInformation.Panel, sv2DPhoto.

However, I still have the problem that I want to use the ResizeViews & lblInformation.SetLayout commands in Activity_Resume. The reason for this is that they are used to change the size & position of controls when the screen's orientation is changed, particularly because the text size for each database row displayed will be different: the idea comes from dlfallen's thread entitled "Multiple screens - one way to do it". There's something strange about embedding a Label in a ScrollView for text vertical scrolling because exactly the same technique works OK for the photo used in my app when using the third party sv2d library (i.e. sv2dPhoto using ivPhoto to define the position & size of the actual photo). Currently, the only solution that I can see is to remove the lblInformation view (if present) and add it again in Activity_Pause. Is that reasonable?
 

johnaaronrose

Active Member
Licensed User
Longtime User
Success

I finally figured it out. My coding is correct except:
I needed to save lblInformation.Height in a Process_Globals Private variable named InformationHeight (after using StrUtil.MeasureMultilineTextHeight) in DisplayDetails sub. InformationHeight is also calculated & saved in the same way in Activity_Resume (i.e. after ResizeViews is executed to allow for screen orientation change). On Activity_Pause, InformationHeight is obtained from lblInformation.Height. These steps are similar to those used for setting the sv2dPhoto width & height.
 

pixelpop

Active Member
Licensed User
Longtime User
Thanks for good tutorial. I have adapted some of johnaaronrose's code to my project, but I need to embed both the bitmap and the text in a single scrollable window.

If you could maybe modify johnaaronrose's sample to put both the invImage and lblInformation into the same ScrollView, that would be wonderful.

(For a real-world example of what I am trying to do, the CNN app display of news stories is a good one).

Thanks!
 
Last edited:

enrico

Active Member
Licensed User
Longtime User
Panel with horizontal scroll buttons

I can't understand why this code doesn't work.

B4X:
   Dim pnlButtons As Panel
   Dim scvButtons As HorizontalScrollView
   Dim btnHeight, btnWidth As Int
   pnlButtons.Initialize("pnlButtons")
   pnlButtons.Color = Colors.White
   Activity.AddView(pnlButtons, 0, 100%y - 60dip, 100%x, 60dip) 
   scvButtons.Initialize(1000dip,"")
   pnlButtons.AddView(scvButtons, 0, 0, 100%x, 100%y)
   btnHeight = 60dip
   btnWidth = 130dip
   Dim btn(6) As Button
   For i = 0 To 5
      btn(i).Initialize("")
      scvButtons.panel.AddView(btn(i), i * btnWidth, Activity.Height - btnHeight, btnWidth, btnHeight)
   Next
   scvButtons.panel.Width = (i + 1) * btnWidth
   btn(0).SetBackgroundImage(LoadBitmap(File.DirAssets,"button1.png"))
   btn(1).SetBackgroundImage(LoadBitmap(File.DirAssets,"button2.png"))
   btn(2).SetBackgroundImage(LoadBitmap(File.DirAssets,"button3.png"))
   btn(3).SetBackgroundImage(LoadBitmap(File.DirAssets,"button4.png"))
   btn(4).SetBackgroundImage(LoadBitmap(File.DirAssets,"button5.png"))
   btn(5).SetBackgroundImage(LoadBitmap(File.DirAssets,"button6.png"))

Any Help ?
 

klaus

Expert
Licensed User
Longtime User
I would change your code to this:
B4X:
Dim pnlButtons As Panel
Dim scvButtons As HorizontalScrollView
Dim btnHeight, btnWidth As Int
pnlButtons.Initialize("pnlButtons")
pnlButtons.Color = Colors.White
btnHeight = 60dip
btnWidth = 130dip
Activity.AddView(pnlButtons, 0, 100%y - btnHeight, 100%x, btnHeight) 
scvButtons.Initialize(1000dip,"")
pnlButtons.AddView(scvButtons, 0, 0, 100%x, btnHeight)
The problem of your code is this line:
pnlButtons.AddView(scvButtons, 0, 0, 100%x, 100%y)
100%y is the screen height, not the Panel height.

Best regards.
 

enrico

Active Member
Licensed User
Longtime User
Thank you, but I still can only see a white empty panel (horizontal scroll now seems to work).
I can't see the buttons.
 
Last edited:

electronik54

Member
Licensed User
Longtime User
make scrollview background white

:sign0085:
every time i scroll the background of the scrollview turns black(i am using samsung galaxy tab 2.2.1) how do i make scrollview background white. i dont want to do it using image.
i would like something like we have <HlistLV.ScrollingBackgroundColor = Colors.White> for list view
 
Top