Is there a way to determine the current scroll offset or scroll position of a GridView?
View.getScrollY() // Underlying var is not updated during a scroll.
I have tried setting an OnScrollListener but the onScroll callback is not fine grained enough for my purposes.
Here is the how I'm attempting to determine the scroll offset using an OnScrollListener.
private int getScrollY() {
int top = 0;
if (mGridView.getChildCount() > 0) {
final View firstView = mGridView.getChildAt(0);
top = firstView.getTop();
}
return top;
}
The issue with this code is that the returned y offset is inaccurate when scrolling upwards; the top view is recycled and hence, the y offset seems to jump;
Is there a nice way of calculating the scroll offset of a GridView? I can't seem to find a good solution.
Use this.
public class CustomGridView extends GridView {
public CustomGridView(Context context) {
super(context);
}
public CustomGridView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/* ADD THIS */
#Override
public int computeVerticalScrollOffset() {
return super.computeVerticalScrollOffset();
}
}
Returns an int value when called
You can use GridView.getFirstVisiblePosition().
http://developer.android.com/reference/android/widget/AdapterView.html#getFirstVisiblePosition()
Related
Write a Custom ListView like:
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
Log.d("onLayout","onLayout=====");
}
}
As I know, when the layout attribute of view has changed, in order to apply the change ( invalide() or requestLayout() ),its parent's onLayout method should be called and layout its children.
So when I scroll the ListView, the layout attribute of its child view has changed, but onLayout doesn't called at all. Why?
Finally I realized relayout a ViewGroup don't need always call onLayout()/layout() method.There are many ways to change views position in ViewGroup,but each way must call onDraw() to write the changed position in FrameBuffer in order to show it in Screen.(Please tell whether I'm wrong with this)
In ListView,I had debug the source code,and when scroll ListView, the stack trace is:
`
trackMotionScroll:5023, AbsListView (android.widget)
scrollIfNeeded:3424, AbsListView (android.widget)
startScrollIfNeeded:3352, AbsListView (android.widget)
onTouchMove:3793, AbsListView (android.widget)
onTouchEvent:3651, AbsListView (android.widget)
dispatchTouchEvent:9294, View (android.view)
in trackMotionScroll,it will call ViewGroup#offsetChildrenTopAndBottom(incrementalDeltaY)
public void offsetChildrenTopAndBottom(int offset) {
final int count = mChildrenCount;
final View[] children = mChildren;
boolean invalidate = false;
for (int i = 0; i < count; i++) {
final View v = children[i];
v.mTop += offset;
v.mBottom += offset;
if (v.mRenderNode != null) {
invalidate = true;
v.mRenderNode.offsetTopAndBottom(offset);
}
}
if (invalidate) {
invalidateViewProperty(false, false);
}
notifySubtreeAccessibilityStateChangedIfNeeded();
}
This will cause the reLayout of ListView.
So I got a conclusion,you don't need obey the framework's measure()–layout()–draw() procedure,but only change view's layout attribute and invalidate,it will also change view's layout.
And I guess ListView dispense with layout() when scroll will improve its efficiency
I want to scroll my RecyclerView to a specific position with offset. Now I am using scrollToPositionWithOffset(position, offset) and this method works fine except the scroll happens too fast and I cant control the speed of the scroll. I've tried using smoothScrollToPosition() but I need the offset. Can someone tell me how can I control the speed of scrolling when using scrollToPositionWithOffset()?
If you need to control fling speed , you need to implement your own recyclerview implementaion .
public class CustomRecyclerView extends RecyclerView {
Context context;
public CustomRecyclerView(Context context) {
super(context);
this.context = context;
}
public CustomRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean fling(int velocityX, int velocityY) {
velocityY *= 0.7;
// velocityX *= 0.7; for Horizontal recycler view. comment velocityY line not require for Horizontal Mode.
return super.fling(velocityX, velocityY);
}
}
put your recyclerview in nestedScrollview it will scroll smoothly.
I was recently working with ImageButtons and I came across this new type of ImageButton 'VisibilityAwareImageButton'. It would be really helpful if someone could tell me the usage of this ImageButton and how is it different from the regular ImageButton? Thanks in advance :)
Here's the full source for VisibilityAwareImageButton.
class VisibilityAwareImageButton extends ImageButton {
private int mUserSetVisibility;
public VisibilityAwareImageButton(Context context) {
this(context, null);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mUserSetVisibility = getVisibility();
}
#Override
public void setVisibility(int visibility) {
internalSetVisibility(visibility, true);
}
final void internalSetVisibility(int visibility, boolean fromUser) {
super.setVisibility(visibility);
if (fromUser) {
mUserSetVisibility = visibility;
}
}
final int getUserSetVisibility() {
return mUserSetVisibility;
}
}
It appears to be almost exactly the same as a regular ImageButton, only it keeps track of the last visibility actually set by the user. The only usage I can find is in the FloatingActionButton source. It is used to keep track of what the user wants the visibility of the view to be while it does it's own internal changes and animations. i.e.
if (child.getUserSetVisibility() != VISIBLE) {
// The view isn't set to be visible so skip changing it's visibility
return false;
}
It's in the design support library and has package visibility, so it seems like Google intends on using it internally (and seemingly only for the FAB implementation at this time).
I am creating a custom imageview and I am trying to find the height of the parent. The only detail I know about the parent is that it would potentially scroll. The reason I need the parent's height is because I am trying to figure out the imageview's position on the screen. I have made an equation that works for accurately calculating its position, but it only works when I manually enter in the parents height. Is there any way to retrieve this information or is there another way to get my imageview's position on the screen every time it changes?
Try this way
public class MyImageView extends ImageView {
int parentHeight;
int parentWidth;
public MyImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyImageView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if(((View)this.getParent()).getMeasuredWidth()!=0){
parentHeight = ((View)this.getParent()).getMeasuredHeight();
parentWidth = ((View)this.getParent()).getMeasuredWidth();
}
}
}
In my application, initially I'm setting opacity of TextView to 60.
After that, when the user presses a button, I want to decrease or increase the opacity of the TextView as per pressing in a button that increases it or a button that decreases it.
I have tried this, but every time when I get the opacity of text view its -3 or -1 which is actually not.
public void decreaseOpacity(View v){
int op=txtView.getBackground().getOpacity();// its alwz -ve value
txtView.getBackground().setAlpha(op-1);
}
try this code
public class AlphaTextView extends TextView {
public AlphaTextView(Context context) {
super(context);
}
public AlphaTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AlphaTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onSetAlpha(int alpha) {
setTextColor(getTextColors().withAlpha(alpha));
setHintTextColor(getHintTextColors().withAlpha(alpha));
setLinkTextColor(getLinkTextColors().withAlpha(alpha));
return true;
}
}
Drawable.getOpacity() dos not take into account changes made by setAlpha(). See the docs:
Note that the returned value does not take into account a custom alpha
or color filter that has been applied by the client through the
setAlpha(int) or setColorFilter(ColorFilter) methods.
You may need to store the alpha value as a variable and not use getOpacity(), on example:
private int mTextViewAlpha = 255;
public void decreaseOpacity(View v){
if ( mTextViewAlpha-- <= 0 ) mTextViewAlpha = 0;
txtView.getBackground().setAlpha(mTextViewAlpha);
txtView.getBackground().invalidateSelf();
}