I am doing an app with gallery with showing a few images, when I scroll the images, they move and jump after a certain point. How do I make them smooth? Any sample code would be of great help.
I had similar problem. Looks like it can be caused by changes in layout, e.g. if you change text in textview which has wrap_content width. This cases layout change and probably forces gallery to update itself and it snaps right on current item.
I was able to fix it by playing with layout, setting fixed sizes where I could etc. but I don't know about permanent and reliable solution
EDIT: also I found this hack if above doesn't work for you
http://www.unwesen.de/2011/04/17/android-jittery-scrolling-gallery/
I managed to solve this problem by overriding the onLayout() method in the Gallery parent and then ignoring any calls where the changed flag was not true.
public class MyGallery extends Gallery {
public MyGallery(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
super.onLayout(changed, l, t, r, b);
}
}
}
I found the above Gallery extends solution to work fairly well. However it was still causing some jitter. By simply overriding the onLayout method and look for number of views on screen I ended up with a "smooth as silk" Gallery view.
Note that I use this for a full screen slideshow effect.
public class SmoothGallery extends Gallery {
public SmoothGallery(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int viewsOnScreen = getLastVisiblePosition() - getFirstVisiblePosition();
if(viewsOnScreen <= 0)
super.onLayout(changed, l, t, r, b);
}
}
Related
So I'm working on creating a dialog fragment to allow user to choose from some options. I have a pretty simple layout inside a constraint layout. TextView on top, recycler view, then two buttons at the bottom.
The problem is, I want the recyclerview to be wrap content, so that if there aren't a lot of options, the dialog will shrink down. However, if there are a lot of options, i'd like it to expand but then start scrolling so all views are visible on the screen.
I can't seem to get past the situation where either it constantly is large. Or if I just allow wrap content, the dialog will grow so large the bottom buttons are missing.
I'm assuming it has something to do with some particular constraint options, but I can't figure out the combination. Any ideas?
EDIT: I know an easy answer is to set a max height on the recycler view. I'm hoping to do that same thing but with constraints, so its not a fixed hard height.
EDIT2: It looks like the constraints will work nicely with wrap as default if the view model's height is fixed. I really can't deal with a fixed height view model though...
Thanks
Create a customRecyclerView that override onMeasure method.
public class CustomRecyclerView extends RecyclerView{
public CustomRecyclerView (Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomRecyclerView (Context context) {
super(context);
}
public CustomRecyclerView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
you can call the recyclerview like this
<com.example.yourpackage.CustomRecyclerView>
I was wondering how I would go about drawing multiple bitmaps on one screen. I want to have a drawing area that I can scroll across multiple bitmaps and view the drawing that are on each bitmap. For example there would be an 2x2 tiled area that I want to scroll across. I'm having trouble figuring out how I would go about showing part of either 2 or 4 bitmaps while I would be scrolling.
EDIT: This is what it would look like
I would suggest creating your won implementation of a viewgroup using this model:
public class MyLayout extends ViewGroup{
public MyLayout(Context c, AttributeSet attr){
super(c, attr);
//Add this to be albe to draw by yourself
this.setWillNotDraw(false);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
#Override
public onDraw(Canvas c){
super.onDraw(c);
//Do all your drawing in here
//You can use canvas.drawBitmap etc...
}
}
This is a good tutorial for a custom viewgroup on Android Dev page:
http://developer.android.com/reference/android/view/ViewGroup.html
I am trying to create a custom ViewGroup, and I want to use it with a full screen application. I am using the "requestWindowFeature(Window.FEATURE_NO_TITLE)" to hide the title bar. The title bar is not showing, but it still consuming space on top of the window.
The image above was generated with the following code:
public class CustomLayoutTestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
Button b = new Button(this);
b.setText("Hello");
CustomLayout layout = new CustomLayout(this);
layout.addView(b);
setContentView(layout);
}
}
public class CustomLayout extends ViewGroup {
public CustomLayout(Context context) {
super(context);
}
public CustomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Log.i("CustomLayout", "changed="+changed+" l="+l+" t="+t+" r="+r+" b="+b);
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
final View v = getChildAt(i);
v.layout(l, t, r, b);
}
}
}
(The full Eclipse project is here)
It is interesting to see that it is the Android that is given this space for my custom layout. I am setting the CustomLayout as the root layout of my Activity. In the Log in the "onLayout" is receiving "t=25", and that is what is pushing my layout down. What I don't know is what I am doing wrong that makes Android the "t=25" (which is exactly the height of the title bar).
I am running this code in the Android SDK 2.1, but I also happens in Android 2.2.
EDIT: If I change the CustomLayout class for some default layout (such as LinearLayout), the space disappears. Of course, the default layouts of Android SDK don't create the layout I am trying to create, so that is why I am creating one.
Although the layout I am creating is somewhat complex, this is the smallest code I could create reproducing the problem I have with my layout.
It's not a full answer, but in the meantime you can work around the problem by wrapping your custom layout in a <FrameLayout />
Also, it's worth noting that your layout extends beyond the bottom of the screen. It's shifted down by the title bar height (38 pixels in my emulator)
Edit: Got it. onLayout() (and the corresponding layout() method) specify that the coordinate are not relative to the screen origin, they're relative to the parent ( http://developer.android.com/reference/android/view/View.html#layout%28int,%20int,%20int,%20int%29 ). So the system is telling you that you're at relative coordinates (0, 38), and you're adding it when passing that down to your child, which means that you're saying that your child is at screen coordinates (0, 76), causing the gap.
What you actually want to do is:
v.layout(0, 0, r - l, b - t);
That will put your child Views aligned with the top left corner of your View, with the same width and height as your view.
I had the same issue with a FrameLayout in 2.2
I fixed it by adding android:layout_gravity="top" to the FrameLayout
I am using TableLayout. which have 100 of items to make it scrollable I am using Tablelayout inside ScrollView. But I have to detect whether the user have scrolled to the last row. If the user have scrolled to the last view then user will be shown a Toast message.
But How to know that the user has scrolled to the last row of the tablelayout. I have referred the code from TableLayout inside ScrollView.
http://huuah.com/using-tablelayout-on-android/
If new scrolled y position + scroll view height >= tableview height that means you have reached the end of list.
To achieve this you have to write your custiom scrollview.
Step-1 You have to create custom scroll view extending ScrollView
package com.sunil;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ScrollView;
public class LDObservableScrollView extends ScrollView {
private LDObservableScrollViewListener scrollViewListener = null;
public LDObservableScrollView(Context context) {
super(context);
}
public LDObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LDObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(LDObservableScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if(scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
Step-2 Create a Listener to detect scrollchanged
package com.sunil;
import LDObservableScrollView;
public interface LDObservableScrollViewListener {
void onScrollChanged(LDObservableScrollView scrollView, int x, int y, int oldx, int oldy);
}
Step-3 in layout xml instead of ScrollView use the custom scroll view
<com.abc.LDObservableScrollView android:layout_width="fill_parent" android:layout_marginTop="1dip"
android:id="#+id/OLF_ScrollView" android:layout_height="fill_parent" android:background="#drawable/small_list_back">
<TableLayout android:layout_width="fill_parent" android:id="#+id/OLF_tableLayout_TableLayout" android:layout_height="fill_parent">
</TableLayout>
</com.abc.LDObservableScrollView>
Step-4 In your activity class or where you want to detect the scroll event use the follwoing code
public class DetectHere implements LDObservableScrollViewListener{
...
LDObservableScrollView scrollView = (LDObservableScrollView)view.findViewById(R.id.OLF_ScrollView);
scrollView.setScrollViewListener(this);
.....
#Override
public void onScrollChanged(LDObservableScrollView scrollView, int x,
int y, int oldx, int oldy) {
// TODO Auto-generated method stub
if((scrollView.getHeight()+y) >= tableLayout.getHeight()){
Log.e("Custom Listener ", "END OF LIST OCCURRED ::");
}
}
This also worked for me, but my y value on the onScrollChanged never gets higher than the height on my samsung galaxy tab 2 7".
But it works on the galaxy tab 2 10.1"
Any ideas why?
[Edit]
I've seen now that this occurs when the screen is less than a certain height, 1000px for instance. Because when I made the content of my scroll less than 1200 on the 10.1" Galaxy tab 2, it stopped working for the maximum height detection.
[Edit]
I've found the solution, it wasn't detecting the size of the scroll correctly, in order to do that, what I've done was the following:
protected void onScrollChanged(int horizontalScrollPosition, int verticalScrollPosition, int previousHorizontalScrollPosition, int previousVerticalScrollPosition) {
int scrollTotalHeight = this.getChildAt(0).getHeight() - super.getHeight();
if(_previousImage != null)
if(verticalScrollPosition <= 0) _previousImage.setVisibility(View.GONE);
if(_nextImage != null)
if(verticalScrollPosition >= scrollTotalHeight) _nextImage.setVisibility(View.GONE);
super.onScrollChanged(horizontalScrollPosition, verticalScrollPosition, previousHorizontalScrollPosition, previousVerticalScrollPosition);
}
public class SynchronisedScrollView extends ListView {
private ScrollViewListener scrollViewListener = null;
public SynchronisedScrollView(Context context) {
super(context);
}
public SynchronisedScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public SynchronisedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
Log.d("Hello", "I am scrolled");
// super.onScrollChanged(x, y, oldx, oldy);
}
}
I want to catch how much the listView is scrolled, so I extend ListView. I am able to scroll the list. But OnScrollChanged is not called. For ScrollView and HorizontalScrollView OnScrollChanged is called whenever it scrolls. Which function is triggered when we scroll a ListView.
In ListView you must explicitly register an onScrollListener to receive onScroll() events.
I think that the method you are looking for is:
public void offsetChildrenTopAndBottom(int offset) {
// ...
}
from ViewGroup. What you can do is extend ListView to gather the offset given to one of the ListViews and pass it though to the other ListView. Make sure that you call super.offsetChildrenTopAndBottom on the recieven end or you could easily end up with a stackoverflow.
I would create a private method and have the new Observable views.
public class ObservableListView extends ListView {
private ObservableListView peer;
// [Constructors] make sure you override all the super constructors.
// Can have trouble with layouts otherwise
public void setPeer(ObservableListView peer) {
this.peer = peer;
}
#Override
public void offsetTopAndBottom(int offset) {
super.offsetTopAndBottom(offset);
if (peer != null) {
peer.internalVerticalOffset(offset);
}
}
private void internalVerticalOffset(int offset) {
super.offsetTopAndBottom(offset);
}
}
If you feel brave you can also define an xml property to give one of the ListViews id and let that one set up the peer relation. (I can expand if you are interested)
My bad, this is non working code. I'm trying to figure out how to do this with the hidden method. In this code I'm overriding the wrong method. Will update shortly.
Update:
Ok, after some research I think that the best option is to combine the extension of ListView with a TouchDelegate.