1cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes/* 2cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * Copyright (C) 2016 The Android Open Source Project 3cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * 4cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * you may not use this file except in compliance with the License. 6cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * You may obtain a copy of the License at 7cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * 8cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 9cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * 10cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * Unless required by applicable law or agreed to in writing, software 11cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * See the License for the specific language governing permissions and 14cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * limitations under the License. 15cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes */ 16cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes 17cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banespackage android.support.v4.widget; 18cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes 19cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banesimport android.os.Build; 20cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banesimport android.support.annotation.NonNull; 219b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikasimport android.view.View; 22cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banesimport android.widget.ListView; 23cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes 24cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes/** 259df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * Helper for accessing features in {@link ListView} 26cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes */ 27cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banespublic final class ListViewCompat { 28cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes 29cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes /** 30cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * Scrolls the list items within the view by a specified number of pixels. 31cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * 32cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * @param listView the list to scroll 33cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes * @param y the amount of pixels to scroll by vertically 34cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes */ 35cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes public static void scrollListBy(@NonNull ListView listView, int y) { 36cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes if (Build.VERSION.SDK_INT >= 19) { 379df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov // Call the framework version directly 389b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas listView.scrollListBy(y); 39cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes } else { 409df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov // provide backport on earlier versions 419b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas final int firstPosition = listView.getFirstVisiblePosition(); 429b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas if (firstPosition == ListView.INVALID_POSITION) { 439b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas return; 449b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas } 459b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas 469b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas final View firstView = listView.getChildAt(0); 479b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas if (firstView == null) { 489b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas return; 499b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas } 509b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas 519b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas final int newTop = firstView.getTop() - y; 529b1c00c9dcde0d65352a2e7d9aaa38710b18d1b9Aurimas Liutikas listView.setSelectionFromTop(firstPosition, newTop); 53cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes } 54cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes } 55cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes 569df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov /** 579df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * Check if the items in the list can be scrolled in a certain direction. 589df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * 599df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * @param direction Negative to check scrolling up, positive to check 609df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * scrolling down. 619df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * @return true if the list can be scrolled in the specified direction, 629df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * false otherwise. 639df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov * @see #scrollListBy(ListView, int) 649df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov */ 659df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov public static boolean canScrollList(@NonNull ListView listView, int direction) { 669df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov if (Build.VERSION.SDK_INT >= 19) { 679df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov // Call the framework version directly 689df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov return listView.canScrollList(direction); 699df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } else { 709df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov // provide backport on earlier versions 719df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov final int childCount = listView.getChildCount(); 729df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov if (childCount == 0) { 739df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov return false; 749df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } 759df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov 769df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov final int firstPosition = listView.getFirstVisiblePosition(); 779df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov if (direction > 0) { 789df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov final int lastBottom = listView.getChildAt(childCount - 1).getBottom(); 799df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov final int lastPosition = firstPosition + childCount; 809df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov return lastPosition < listView.getCount() 819df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov || (lastBottom > listView.getHeight() - listView.getListPaddingBottom()); 829df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } else { 839df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov final int firstTop = listView.getChildAt(0).getTop(); 849df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov return firstPosition > 0 || firstTop < listView.getListPaddingTop(); 859df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } 869df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } 879df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov } 889df73e86fb0949ee8c5afee0bf519982f59c016dKirill Grouchnikov 89cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes private ListViewCompat() {} 90cc7e6ffce76f2066838b626ac04536b95a0689c3Chris Banes} 91