In my application within a scroll view, I am using list view. But the list view is not scrolling. Can anyone suggest me what should i do.
I searched for it and find out that the list view don't scroll within scroll view.
Any solution?
You can create your own list view and set expand to false. Here is the sample class
public class ExpandableHeightListView extends ListView {
boolean expanded = false;
public ExpandableHeightListView(Context context) {
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
You can use like this your activity.clas
ExpandableHeightListView listview = (ExpandableHeightListView) findViewById(R.id.list);
listview.setExpanded(true);
In your layout file you can use ExpandableHeightListView at the place of list view within a scroll view. It will scroll.
Exclude ListView from ScrollView, because ListView already have scrolling mechanism in it.
Don't put a listview inside a scrollview.
The listview already handles scrolling so it doesn't need to be inside a scrollview.
You should change your layouts to reflect this.
ListView Inside Scroll View will not work . Put it out side of that . Because both have scrolling feature so scroll will not work when thay will come together .
Use this Class.
public class CustomScrollView extends ScrollView {
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public boolean onTouchEvent(MotionEvent ev) {
return true;
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
And in your xml layout change your scrollview tag with the package name and class of the CustomScrollView. i.e. change to com.test.CustomScrollView.
And inside you Activity get the id of the custom scroll view and include this code.
private int currentX, currentY;
private CustomScrollView customScrollView;
customScrollView.setSmoothScrollingEnabled(true);
customScrollView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction()){
case MotionEvent.ACTION_DOWN: {
currentX = (int) event.getRawX();
currentY = (int) event.getRawY();
break;
}
case MotionEvent.ACTION_MOVE: {
#SuppressWarnings("unused")
int x2 = (int) event.getRawX();
int y2 = (int) event.getRawY();
customScrollView.scrollBy(0 , currentY - y2);
currentY = y2;
break;
}
case MotionEvent.ACTION_UP: {
break;
}
}
return true;
}
});
Don't put a listView inside a ScrollView.
You should read the Romain Guy answer and the comment above:
How can I put a ListView into a ScrollView without it collapsing?
You can exclude ListView from Scroll view.
If you would like to have a "list" inside a scrollView you could use a LinearLayout. Something like this:
public class MyListLayout extends LinearLayout implements
View.OnClickListener {
private Adapter list;
private View.OnClickListener mListener;
public MyListLayout(Context context) {
super(context);
}
public MyListLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EvernoteListLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onClick(View v) {
if (mListener!=null)
mListener.onClick(v);
}
public void setList(Adapter list) {
this.list = list;
//Popolute list
if (this.list!=null){
for (int i=0;i<this.list.getCount();i++){
View item= list.getView(i, null,null);
this.addView(item);
}
}
}
public void setmListener(View.OnClickListener mListener) {
this.mListener = mListener;
}
}
// Create ArrayAdapter
MyListAdapter mListAdapter = new MyListAdapter();
MyListLayout mLay = (MyListLayout) findViewById(R.id.box_list_ev);
if (mLay != null) {
mLay.setList(mListAdapter);
}
The scroll view "eats" all the touches...
You should avoid inserting a scrolling element (ListView) into another scrolling element(scroll view), your user could go crazy.
In these cases I use a LinearLayout in place of the ListView and I inflate into it the customview created to represent each List element, here is an example, fell free to ask me more:
LinearLayout containerLinearLayout= (LinearLayout)findViewById(R.id.containerLinearLayout);
containerLinearLayout.removeAllViews();
for(int i=0;i<array.length();i++){
JSONObject convocazione=array.getJSONObject(i);
View child = getLayoutInflater().inflate(R.layout.list_element_layout,null);
TextView txtDettaglioLuogo=(TextView)child.findViewById(R.id.txtDettaglioLuogo);
TextView txtOra=(TextView)child.findViewById(R.id.txtOra);
txtOra.setText("text");
txtData.setText("more text");
containerLinearLayout.addView(child);
}
import android.content.Context;
import android.widget.ListView;
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, android.util.AttributeSet attrs) {
super(context, attrs);
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
use this
Finally i got the solution for the scrolling issue i got custom scrollview class to manage the scrollview.
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ScrollView;
public class VerticalScrollview extends ScrollView{
public VerticalScrollview(Context context) {
super(context);
}
public VerticalScrollview(Context context, AttributeSet attrs) {
super(context, attrs);
}
public VerticalScrollview(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action)
{
case MotionEvent.ACTION_DOWN:
Log.i("VerticalScrollview", "onInterceptTouchEvent: DOWN super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_MOVE:
return false; // redirect MotionEvents to ourself
case MotionEvent.ACTION_CANCEL:
Log.i("VerticalScrollview", "onInterceptTouchEvent: CANCEL super false" );
super.onTouchEvent(ev);
break;
case MotionEvent.ACTION_UP:
Log.i("VerticalScrollview", "onInterceptTouchEvent: UP super false" );
return false;
default: Log.i("VerticalScrollview", "onInterceptTouchEvent: " + action ); break;
}
return false;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
Log.i("VerticalScrollview", "onTouchEvent. action: " + ev.getAction() );
return true;
}
}
Check the onMeasure source code of the ListView, you will find that if the height measureSpec is UNSPECIFIED then the height of the listview is the height of only one item plus some padding, see below:
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
}
So we can simplily change the height SpecMode to AT_MOST, and the height size is the left height size of its parent.
Below is the solution:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Related
RecyclerView inside NestedScrollView freezes the Activity when loading large amount of data. It loads much faster with ScrollView, but scrolling is affected in that case.
I tried setting attributes like setAutoMeasure and setNestedScrollingEnabled which did not help.
Any suggestions?
Recycling of views is not supported inside NestedScrollViews as I understand, so the suggestion would be to try to change your layout.
This help to increase the speed of recycler view scrolling.
SpeedyLinearLayoutManager linearLayoutManager = new SpeedyLinearLayoutManager(MainActivity.this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
myRecyclerView.setLayoutManager(linearLayoutManager);
SpeedyLinearLayoutManager.class
public class SpeedyLinearLayoutManager extends LinearLayoutManager {
private static final float MILLISECONDS_PER_INCH = 2f; //default is 25f (bigger = slower)
public SpeedyLinearLayoutManager(Context context) {
super(context);
}
public SpeedyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public SpeedyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return SpeedyLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Use Custom list view instead of Recycler view inside scroll view...
Check this Answer
Custom List View
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;
public class ExpandableHeightListView extends ListView {
boolean expanded = true;
public ExpandableHeightListView(Context context) {
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
// Calculate entire height by providing a very large height hint.
// View.MEASURED_SIZE_MASK represents the largest height possible.
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
you can include app:layout_behavior="#string/appbar_scrolling_view_behavior"
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerView"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
or disable the nested scrolling behavior for the recycler view.
recyclerView.setNestedScrollingEnabled(false);
I have a list view inside a scroll view.
To make it work I have created a custom list view from here http://www.londatiga.net/it/programming/android/make-android-listview-gridview-expandable-inside-scrollview/
but this is also not working when there is single item in listview. I am not able to scroll in case of single iteam.
Update:
ExpandableHeightListView.java
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ListView;
/**
* Created by hariram on 10/28/15.
*/
public class ExpandableHeightListView extends ListView {
boolean expanded = false;
public ExpandableHeightListView(Context context) {
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// HACK! TAKE THAT ANDROID!
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(
Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
Now I am using this ExpandableHeightListView instead of list view like
ExpandableHeightListView listView = (ExpandableHeightListView) getView().findViewById(R.id.expandablelistview);
listView.setExpanded(true);
CustomAdapter customAdapter = new CustomAdapter( getActivity(), resultList);
listView.setAdapter(customAdapter);
It's work fine when there is more than one item in list, but it doesn't work in case of single item. I am not able to scrol in case of single listing.
I am trying to create 2-level expandableListView.I can get the data and bind to UI elements perfectly but the height between the two child is fixed.
since inner ExpandableListView is just like inside a scrollview i am seeing only one item.
*group1
^child1
//data
^child2
//data
*group2
^child1
//data
^child2
//dataa
i am setting the height of the child dynamically.i.e the hieght between group1 and group2 using the following method:
ListAdapter listadp = lv_ancillaryservice.getAdapter();
if (listadp != null) {
int totalHeight = 0;
for (int i = 0; i < listadp.getCount(); i++) {
View listItem = listadp.getView(i, null, lv_ancillaryservice);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = lv_ancillaryservice.getLayoutParams();
params.height = totalHeight + (lv_ancillaryservice.getDividerHeight() * (listadp.getCount() - 1));
lv_ancillaryservice.setLayoutParams(params);
lv_ancillaryservice.requestLayout();
I used above because usingwrap_content doesnot work for listview. now the problems are:
when group1 is clicked,^child1 and ^child2 are shownup and when clicked on child1,i have a listview but i am not able to see the full list.(group2 position is fixed)
scrolling is no where working.
i solved this problem by using this link https://github.com/PaoloRotolo/ExpandableHeightListView .
package com.rtt.reeferwatch.utilities;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ExpandableListView;
public class ExpandableHeightListView extends ExpandableListView {
boolean expanded = false;
public ExpandableHeightListView(Context context) {
super(context);
}
public ExpandableHeightListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ExpandableHeightListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public boolean isExpanded() {
return expanded;
}
#Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (isExpanded()) {
int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void setExpanded(boolean expanded) {
this.expanded = expanded;
}
}
I have an ImageView in a FrameLayout, I want to setup LongClickListener but its failing to work, I tried setting up OnTouchListener and its working flawless, I do not have the slightest idea as to why its not working but below is my code code:
public class DragImageView extends FrameLayout implements View.OnLongClickListener {
ImageView ivDrag;
public DragImageView(Context context) {
super(context);
}
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void AddImageView(View draggableObject, int x, int y, int width, int height) {
LayoutParams lpDraggableView = new LayoutParams(width, height);
lpDraggableView.gravity = Gravity.TOP;
lpDraggableView.leftMargin = x;
lpDraggableView.topMargin = y;
if(draggableObject instanceof ImageView) {
this.ivDrag = (ImageView) draggableObject;
ivDrag.setLayoutParams(lpDraggableView);
ivDrag.setClickable(true);
ivDrag.setLongClickable(true);
ivDrag.setOnLongClickListener(this);
this.addView(ivDrag);
}
}
/**
* Draggable object ontouch listener
* Handle the movement of the object when dragged and dropped
*/
private View.OnTouchListener OnTouchToDrag =new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
FrameLayout.LayoutParams dragParam = (LayoutParams) v.getLayoutParams();
switch(event.getAction())
{
case MotionEvent.ACTION_MOVE:
{
dragParam.topMargin = (int)event.getRawY() - (v.getHeight());
dragParam.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
v.setLayoutParams(dragParam);
break;
}
case MotionEvent.ACTION_UP:
{
dragParam.height = v.getHeight();
dragParam.width = v.getWidth();
dragParam.topMargin = (int)event.getRawY() - (v.getHeight());
dragParam.leftMargin = (int)event.getRawX() - (v.getWidth()/2);
v.setLayoutParams(dragParam);
break;
}
case MotionEvent.ACTION_DOWN:
{
dragParam.height = v.getHeight();//fixed on drag and drop
dragParam.width = v.getWidth();
v.setLayoutParams(dragParam);
break;
}
}
return true;
}
};
#Override
public boolean onLongClick(View view) {
ivDrag.setOnTouchListener(OnTouchToDrag);
Toast.makeText(view.getContext(), "OnLongClick", Toast.LENGTH_SHORT).show();
return false;
}
}
I want to setup LongClickListener but its failing to work
You are not receiving the callbacks from OnLongClickListener because it has no set listener. Since your class implements View.OnLongClickListener and you want to receive the callback in your overridden onLongClick() method, add this class itself as the listener and it will work. I've done so in the constructor (choose the appropriate constructor out of the three as per your initialization of the view):
public DragImageView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnLongClickListener(this); // <-- set this class instance as the listener
}
Although I'm surprised how you got it working with OnTouchListener. You probably explicitly added the listener, right?
I am looking for any good solution to make parallax with two Views.
My first view is Fragment and second is ListView.
Fragment have min height equals 200dp and when I want drag listview to down the fragment will grow.
I wrote some code, but it isn't all I need.
public class MyListView extends ListView implements OnTouchListener {
int touchActionDownY, touchActionMoveY;
int parentHeight;
int initialPosition = -1;
TextView viewToMove;
LinearLayout.LayoutParams params;
public MyListView(Context context) {
super(context);
init();
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init () {
setOnTouchListener(this);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
parentHeight = MeasureSpec.getSize(heightMeasureSpec);
initialPosition = (int) getY();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int deltaY = 0;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchActionDownY = (int)event.getY();
touchActionMoveY = touchActionDownY;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
deltaY = (int)event.getY() - touchActionMoveY;
touchActionMoveY = (int)event.getY();
if(getFirstVisiblePosition() == 0 && v.getY() < parentHeight && touchActionMoveY > touchActionDownY && deltaY > 0){
params.height = params.height + deltaY;
viewToMove.setLayoutParams(params);
return true;
} else if(v.getY() > 200 && touchActionMoveY < touchActionDownY && deltaY < 0) {
params.height = params.height + deltaY;;
viewToMove.setLayoutParams(params);
return true;
} else {
}
break;
}
return false;
}
public void setViewToMove(TextView v) {
viewToMove = v;
params = (android.widget.LinearLayout.LayoutParams) viewToMove.getLayoutParams();
}
}
In this ListView I need smooth view scroll when user throw list. (View stoped, because method work with ACTION_MOVE).
Any help?
I need interaction with my first fragment.
Parallax should work when only list is draged.