4

I set a image as Listview background, if I want to scroll it with the item, what can I do?

for example: 1 is the background, if I scroll Listview down, it will change from

        1          
-----1-----1--------
   1         1
-1-------------1----

to

--------1----------
      1    1
---1----------1----
 1              1

maybe I could extends listview and override dispatchDraw, but if I use listFragment, what can I do ? anybody help me?

AndroidLearner
  • 4,500
  • 4
  • 31
  • 62
GeminiYellow
  • 1,016
  • 2
  • 12
  • 34

2 Answers2

6

In your Activity's XML file define the listview like this ::

(Define the property in this xml file as per your requirement)

<com.example.MyCustomListView
    android:id="@+id/listview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>

Create one Class named MyCustomListView ::

    public class MyCustomListView extends ListView
    {

       private Bitmap background;

    public MyCustomListView(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
        background = BitmapFactory.decodeResource(getResources(), R.drawable.yourImageName);
    }

    @Override
    protected void dispatchDraw(Canvas canvas) 
    {
        int count = getChildCount();
        int top = count > 0 ? getChildAt(0).getTop() : 0;
        int backgroundWidth = background.getWidth();
        int backgroundHeight = background.getHeight();
        int width = getWidth();
        int height = getHeight();

        for (int y = top; y < height; y += backgroundHeight)
        {
            for (int x = 0; x < width; x += backgroundWidth)
            {
                canvas.drawBitmap(background, x, y, null);
            }
        }
        super.dispatchDraw(canvas);
    }
 }

Hope this will solve your problem :)

AndroidLearner
  • 4,500
  • 4
  • 31
  • 62
  • thanks, it work. but if listview change to listfragment, what should i do ? – GeminiYellow Nov 20 '12 at 23:40
  • @GeminiYellow if my answer is helpful to you,then upvote my answer as per SO rule and if you have any other query asked separate question and show us what you have tried. – AndroidLearner Nov 21 '12 at 04:51
  • oh,sorry, i should mark your answer now. your answer just a part of my question. it worked,but not completed. listfragment could not apply this solution, now i add an OnLayoutChangeListener to the listview, and change the layout everytime.it will degrade performance. – GeminiYellow Nov 21 '12 at 07:01
  • This solution works, but there is one bug: If there is a paddingTop set to the ListView the area above the first listitem and below the last doesn't scroll. This is a fix for it: replace this line: `int top = count > 0 ? getChildAt(0).getTop() : 0;` with this: `int top = count > 0 ? getChildAt(0).getTop() - getPaddingTop() : 0;`. –  Jan 11 '18 at 11:52
0

The code by AndroidLearner works well, except for one bug, see my comment on AndroidLearner's answer. I wrote a Kotlin version of his code that fixes the bug, and also works with any background that was defined in xml like so:

<ListViewWithScrollingBackground
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/some_background"/>

Here is the code:

import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import android.widget.ListView


class ListViewWithScrollingBackground(context: Context, attrs: AttributeSet)
: ListView(context, attrs) {

  private val background by lazy { getBackground().toBitmap() }

  override fun dispatchDraw(canvas: Canvas) {
    var y = if (childCount > 0) getChildAt(0).top.toFloat() - paddingTop else 0f
    while (y < height) {
      var x = 0f
      while (x < width) {
        canvas.drawBitmap(background, x, y, null)
        x += background.width
      }
      y += background.height
    }
    super.dispatchDraw(canvas)
  }

  private fun Drawable.toBitmap(): Bitmap = 
    if (this is BitmapDrawable && bitmap != null) bitmap else {
    val hasIntrinsicSize = intrinsicWidth <= 0 || intrinsicHeight <= 0
    val bitmap = Bitmap.createBitmap(if (hasIntrinsicSize) intrinsicWidth else 1,
      if (hasIntrinsicSize) intrinsicHeight else 1, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    setBounds(0, 0, canvas.width, canvas.height)
    draw(canvas)
    bitmap
  }

}

For the conversion of the Drawable to a Bitmap I used this post.