How can achieve pinch zoom behavior like Gmail app? I've put header container in ScrollView followed by WebView. Seems It's very complex behavior.
Here is without zoom.
When we pinch Webview upper container scrolled up as per zoom:
So far here is my initials:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/white">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/appbar">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#color/colorPrimary"></FrameLayout>
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:scrollbars="none" />
</LinearLayout>
</ScrollView>
</RelativeLayout>
</FrameLayout>
GMail uses a Chrome WebView with pinch zoom enabled. the zoom only applies to the single thread view. WebSettings setBuiltInZoomControls() is by default false and setDisplayZoomControls() is by default true. by changing both, the zoom works and there are no zoom controls being displayed:
webview.getSettings().setBuiltInZoomControls(true);
webview.getSettings().setDisplayZoomControls(false);
and that toolbar is a transparently styled ActionBar, with style windowActionBarOverlay set true:
Flag indicating whether this window's Action Bar should overlay application content.
the ActionBar's bottom shadow is being removed in the top-most scroll position. this one listens for vertical scroll events and not for any scaling gestures. this effect works about like this (initially that shadow has to be hidden):
webView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
if(scrollY == 0) {
/* remove the ActionBar's bottom shadow */
} else {
/* apply the ActionBar's bottom shadow */
}
}
}
depending how often the OnScrollChangeListener is being triggered, even checking for scrollY == 0 and scrollY == 1 might already suffice to switch the shadow on and off.
when scaling, this seems to be a ScaleGestureDetector.SimpleOnScaleGestureListener (see the docs), where .getScaleFactor() is being used to animate the secondary "toolbar" vertical top position, which then shoves it outside of the visible view-port. and this secondary "toolbar" appears to be a nested vertical DrawerLayout - which cannot be manually moved - that's why it moves that smooth... a DrawerLayout is not limited to be a horizontal drawer; and I think this is the answer.
Edit: I'd relatively certain now, that this is AndroidX with MDC Motion.
I think I understood your question. You want to push the subject line in the upward direction and the other emails in the downward direction when an email is being expanded. I tried to implement the idea of showing an email in the Gmail app. I think I am very close to the solution as the pushing is not smooth enough. However, I wanted to share the answer here to present my thought about your question.
I have created a GitHub repository from where you can see my implementation. I have added a readme there as well to explain the overall idea.
I tried to implement the whole thing using a RecyclerView have different ViewTypes. I have added an adapter which is like the following.
public class RecyclerViewWithHeaderFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int HEADER_VIEW = 1;
private static final int GROUPED_VIEW = 2;
private static final int EXPANDED_VIEW = 3;
private ArrayList<Integer> positionTracker; // Take any list that matches your requirement.
private Context context;
private ZoomListener zoomListener;
// Define a constructor
public RecyclerViewWithHeaderFooterAdapter(Context context, ZoomListener zoomListener) {
this.context = context;
this.zoomListener = zoomListener;
positionTracker = Utilities.populatePositionsWithDummyData();
}
// Define a ViewHolder for Header view
public class HeaderViewHolder extends ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Define a ViewHolder for Expanded view
public class ExpandedViewHolder extends ViewHolder {
public ExpandedViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// Define a ViewHolder for Expanded view
public class GroupedViewHolder extends ViewHolder {
public GroupedViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do whatever you want on clicking the item
}
});
}
}
// And now in onCreateViewHolder you have to pass the correct view
// while populating the list item.
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
if (viewType == EXPANDED_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_expanded, parent, false);
ExpandedViewHolder vh = new ExpandedViewHolder(v);
return vh;
} else if (viewType == HEADER_VIEW) {
v = LayoutInflater.from(context).inflate(R.layout.list_item_header, parent, false);
HeaderViewHolder vh = new HeaderViewHolder(v);
return vh;
} else {
v = LayoutInflater.from(context).inflate(R.layout.list_item_grouped, parent, false);
GroupedViewHolder vh = new GroupedViewHolder(v);
return vh;
}
}
// Now bind the ViewHolder in onBindViewHolder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
try {
if (holder instanceof ExpandedViewHolder) {
ExpandedViewHolder vh = (ExpandedViewHolder) holder;
vh.bindExpandedView(position);
} else if (holder instanceof GroupedViewHolder) {
GroupedViewHolder vh = (GroupedViewHolder) holder;
} else if (holder instanceof HeaderViewHolder) {
HeaderViewHolder vh = (HeaderViewHolder) holder;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// Now the critical part. You have return the exact item count of your list
// I've only one footer. So I returned data.size() + 1
// If you've multiple headers and footers, you've to return total count
// like, headers.size() + data.size() + footers.size()
#Override
public int getItemCount() {
return DEMO_LIST_SIZE; // Let us consider we have 6 elements. This can be replaced with email chain size
}
// Now define getItemViewType of your own.
#Override
public int getItemViewType(int position) {
if (positionTracker.get(position).equals(HEADER_VIEW)) {
// This is where we'll add the header.
return HEADER_VIEW;
} else if (positionTracker.get(position).equals(GROUPED_VIEW)) {
// This is where we'll add the header.
return GROUPED_VIEW;
} else if (positionTracker.get(position).equals(EXPANDED_VIEW)) {
// This is where we'll add the header.
return EXPANDED_VIEW;
}
return super.getItemViewType(position);
}
// So you're done with adding a footer and its action on onClick.
// Now set the default ViewHolder for NormalViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {
// Define elements of a row here
public ViewHolder(View itemView) {
super(itemView);
// Find view by ID and initialize here
}
public void bindExpandedView(final int position) {
// bindExpandedView() method to implement actions
final WebView webView = itemView.findViewById(R.id.email_details_web_view);
webView.getSettings().setBuiltInZoomControls(true);
webView.getSettings().setDisplayZoomControls(false);
webView.loadUrl("file:///android_asset/sample.html");
webView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
#Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
zoomListener.onZoomListener(position);
}
});
}
}
}
And the expanded list item contains a WebView which has a wrapper which is wrap_content. You will find the following layout in the list_item_expanded.xml.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<WebView
android:id="#+id/email_details_web_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white"
android:scrollbars="none"
tools:ignore="WebViewLayout" />
</RelativeLayout>
I tried to add some dummy data for the experiment and hence the Utility class was written. The RecyclerView is set to have a reverse layout as this is the common expectation of showing a conversation in a RecyclerView.
The key idea is to scrollToPosition when the WebView is being expanded. So that it feels like the items are push upwards and downwards to accommodate the expansion. Hope you get the idea.
I am adding some screenshots here to give you an idea about what I could achieve so far.
Please note that the pushing mechanism is not smooth. I will be working on this. However, I thought I should post it here as this might help you in your thinking. I would like to suggest you clone the repository and run the application to check the overall implementation. Let me know if there is any feedback.
I tried to implement this behaviour using webview.setBuiltInZoomControls() and ScaleGestureDetector by overriding WebView and feeding all motion events to detector. It works, but scale detector and zoom work a bit different and UX turns out to be terrible.
If you look closely at Gmail zoom implementation and a webview zoom you will see they are different. I believe the Gmail zoom is based on view.setScaleX() and view.setScaleY(). You can get a basic behaviour by subclassing WebView and following this guide. You may also need to call view.setPivotX() and view.setPivotY(). Gmail implementation is more complex since it has scroll and seems to scroll the content up while you zoom in. You can try to use some library that implements the zoomable container and supports scrolling, like this one. However I was unable to make it work properly with WebView.
Overall it's a complex task and you have to play with the implementation yourself to make some compromises and get a similar but decent UX.
Related
I want to use recylerview to show a large vertical data set with a large amount of data on each row
I am currently using the LinearLayoutManager
Each row has it's own ViewHolder where I hold a "RowView" object. Each RowView is a fixed width.
public class EventsRecylerAdapter extends RecyclerView.Adapter<EventsRecylerAdapter.ViewHolder>
{
private Context mContext;
private ArrayList<EventsStrip.Item> mItems;
public EventsRecylerAdapter(Context context, ArrayList<EventsStrip.Item> items) {
mContext = context;
mItems = items;
}
#Override
public EventsRecylerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
EventRowView v = new EventRowView(mContext);
ViewHolder vh = new ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
EventsStrip.Item item = mItems.get(position);
holder.mEventRowView.initItem(item);
}
#Override
public int getItemCount() {
return mItems.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public EventRowView mEventRowView;
public int getMeasuredHeight() {
mEventRowView.measure(0, 0);
return mEventRowView.getMeasuredHeight();
}
public ViewHolder(EventRowView v) {
super(v);
mEventRowView = v;
}
}
}
Here is the code in my "EventsView" container that has the
protected void init(Context context) {
setOrientation(LinearLayout.VERTICAL);
ViewGroup.LayoutParams params = (ViewGroup.LayoutParams) getLayoutParams();
if (null == params)
params = generateDefaultLayoutParams();
params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
params.width = ViewGroup.LayoutParams.WRAP_CONTENT;
setLayoutParams(params);
mHeaderScrollView = (HorizontalScrollView) findViewById(R.id.headerScrollView);
mHeaderScrollView.getViewTreeObserver().addOnScrollChangedListener(new HeaderScrollViewListener());
mRecyclerView = (RecyclerView) findViewById(R.id.EventsRecylerView);
mRecyclerView.addOnScrollListener(new RecyclerScrollListener());
// use a linear layout manager
mLayoutManager = new LinearLayoutManager(mActivity);
mRecyclerView.setLayoutManager(mLayoutManager);
}
Since each row each wider than the device I would like to enable a horizontal scrollbar so I can scroll sideways to see more data in each row. Currently I am seeing all the data that I would expect to see just clipped at the edge of the screen.
Also, I would like to scroll horizontally programatically. When I call scrollTo(newxvalue, recylerview.getScrollY()) nothing happens. I don't want to scroll to a new position in the adapter list. I want to see more data that is currently "off screen" on the items currently on the screen. I have a static header at the top of the "list" with a horizontal scroll view on it. As the user drags the header I want the list below to stay in sync.
Any help/guidance would be appreciated
This turned out to be a lot simpler than I thought.
In a list view you will get unpredictable results if you put a list view inside a ScrollView . However in the case I simply put the header view and the RecylerView with a vertical linear layout manager inside of a horizontal ScrollView and it seems to behave as intended (i.e. RecylerView does not have the same limitations as ListView).
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/headerScrollView"
>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="#color/navigation_bar_color"
android:id="#+id/eventRowLayout"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:paddingLeft="2dp"
android:layout_alignParentTop="true" />
<android.support.v7.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/EventsRecylerView"
android:layout_below="#+id/eventRowLayout">
</android.support.v7.widget.RecyclerView>
</RelativeLayout>
</HorizontalScrollView>
I want to create below layout under which item will scroll vertically. whenever we scroll up or down the centered(28) textview should be zoom in position.i found this link Gallery like view with center image zoom but they scroll horizontally using image based on their requirement. i need vertically scroll only using textview
please let me know if any body know the logic.......
First of all, thanks to #sanjay kumar had a good question.
After 2 days, I found a best solution for this question.
You can use RecyclerView and make sure the LinearLayoutManager should like this
LinearLayoutManager yourLinearLayout= new LinearLayoutManager(getApplicationContext());
yourLinearLayout.setOrientation(LinearLayoutManager.VERTICAL);
yourLinearLayout.setLayoutManager(yearLayoutManager);
The most difficult problem is how can you get the middle Item of recyclerView, well I think you can learn more in this link:
https://github.com/plattysoft/SnappingList
Finally, to make the middle Item bigger than the others. In the RecyclerView's Adapter should be like this
public class DateAdapter extends RecyclerView.Adapter<DateAdapter.DateViewHolder> {
private ArrayList<LabelerDate> dateDataList;
private static final int VIEW_TYPE_PADDING = 1;
private static final int VIEW_TYPE_ITEM = 2;
private int selectedItem = -1;
public DateAdapter(ArrayList<Datasource> data, int paddingWidthDate) {
this.dateDataList = data;
this.paddingWidthDate = paddingWidthDate;
}
#Override
public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//todo
}
#Override
public void onBindViewHolder(DateViewHolder holder, int position) {
Datasource data = dateDataList.get(position);
if (getItemViewType(position) == VIEW_TYPE_ITEM) {
holder.tvDate.setText(String.valueOf(data.valueDate));
holder.tvDate.setVisibility(View.VISIBLE);
holder.imgSmall.setVisibility(View.VISIBLE);
if (position == selectedItem) {
holder.tvDate.setTextColor(Color.parseColor("#094673"));
holder.tvDate.setTextSize(35);
holder.imgSmall.setBackgroundResource(R.color.textviewbold);
} else {
holder.tvDate.setTextColor(Color.GRAY);
holder.tvDate.setTextSize(35);
holder.imgSmall.setBackgroundResource(R.color.gray);
}
}
}
public void setSelecteditem(int selecteditem) {
this.selectedItem = selecteditem;
notifyDataSetChanged();
}
#Override
public int getItemViewType(int position) {
//todo
}
public class DateViewHolder extends RecyclerView.ViewHolder {
//todo
}}
After created The recyclerView, adapter and datasource. You can look at the onBindViewHolder(). If Item is selected then it's become bigger and change to black. If is not selected it will become Gray. My layout look like yours
use this library
Polidea view library
Put your TextView into a LinearLayout that lives on a ZoomView.
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.polidea.ZoomView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="#+id/myLinearLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</com.polidea.ZoomView>
</ScrollView>
The Polidea custom View didn't work in my case, as is. Had to a add a constructor with AttributeSet parameter, because it threw an xml inflation error. Also I had to make the ScrollView wrap only the TextView.
Previously, I implemented Google+ card liked animation (Video), by using technique mentioned in New Google Now and Google+ card interface
Override LinearLayout's onGlobalLayout to start animation, so that when activity first launched, we can see the slide up animation of cards.
Override ScrollView's onScrollChanged to start animation, so that during scrolling, we can see the newly visible cards being animated.
So far, I don't see any technique from RecylerView's example.
I was wondering, without using LinearLayout and ScrollView, can with achieve the same outcome, by using RecylerView? Is there any code example available? (So far, I unable to find one yet)
Add these lines in RecyclerView 's adaptor. Make a Variable for Each card i.e(convertView) here and initialise it.
int mLastPosition = 0;
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView card_head, card_body;
View convertView;
#SuppressLint("NewApi")
public ViewHolder(View v) {
super(v);
convertView = v;
}
}
Bind you view by position
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
// do your thing here
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
float initialTranslation = (mLastPosition <= position ? 150f
: -150f);
holder.convertView.setTranslationY(initialTranslation);
holder.convertView.animate()
.setInterpolator(new DecelerateInterpolator(1.0f))
.translationY(0f).setDuration(900l).setListener(null);
}
// Keep track of the last position we loaded
mLastPosition = position;
}
here , you have to animate the who view it calls onBindViewHolder method when new card is created animate the whole view customize it.
I have code like this
public static class MyViewHolder extends RecyclerView.ViewHolder {
#InjectView(R.id.text)
TextView label;
public MyViewHolder(View itemView) {
super(itemView);
ButterKnife.inject(this, itemView);
}
public void hide(boolean hide) {
label.setVisibility(hide ? View.GONE : View.VISIBLE);
}
}
which maps to a single row in a RecyclerView. R.id.text is in fact the root view of the layout that gets inflated and passed in to the constructor here.
I'm using the default implementation of LinearLayoutManager.
In bindViewHolder, I call hide(true) on an instance of MyViewHolder, but instead of collapsing the row as expected, the row becomes invisible, maintaining its height and position in the RecyclerView. Has anyone else run into this issue?
How do you hide items in a RecyclerView?
There is no built in way to hide a child in RV but of course if its height becomes 0, it won't be visible :). I assume your root layout does have some min height (or exact height) that makes it still take space even though it is GONE.
Also, if you want to remove a view, remove it from the adapter, don't hide it. Is there a reason why you want to hide instead of remove ?
Put method setVisibility(boolean isVisible) in ViewHolder.
You can change itemView params(width and height) for LayoutManager:
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
...
public void setVisibility(boolean isVisible){
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams)itemView.getLayoutParams();
if (isVisible){
param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
itemView.setVisibility(View.VISIBLE);
}else{
itemView.setVisibility(View.GONE);
param.height = 0;
param.width = 0;
}
itemView.setLayoutParams(param);
}
public ViewHolder(View itemView) {
super(itemView);
...
}
}
and change visibility for ItemDecoration (Divider):
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
...
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
...
for (int i = 0; i < parent.getChildCount(); i++) {
if (parent.getChildAt(i).getVisibility() == View.GONE)
continue;
/* draw dividers */
}
}
}
You CAN do it!
First, you need to detect which position of item that you want to hide. You can custom getItemViewType to do it.
Next, on onCreateViewHolder, depend on the view type. You can do something like this:
if(viewType == TYPE_HIDE) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.empty_item, parent, false);
vHolder = new ViewHolder(context, v, viewType, this);
break;
}
return vHolder;
-> empty item is a layout that have nothing, (in other word, it is default layout whenever created). or code:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
Hope it help!
Okay, so the way I did it in the end was I had my whole dataset, say, myObjects and I had scenarios where I would only want to show subsets of that dataset.
Since setting visibility of rows in RecyclerView doesn't cause the heights to collapse, and setting the heights of the rows did not appear to do anything either, what I had to do was just keep a secondary dataset called myObjectsShown which was nothing more than a List<Integer> that would index into myObjects to determine which objects would be displayed.
I would then intermittently update myObjectsShown to contain the correct indices.
Therefore,
public int getItemCount() {
return myObjectsShown.size();
}
and
public void onBindViewHolder(MyViewHolder holder, int position) {
Object myObject = myObjects.get(myObjectsShown.get(position));
// bind object to viewholder here...
}
For hiding view in RecyclerView I hide/show view in OnBindViewHolder:
if (item.isShown) {
vh.FooterLayout.setVisibility(View.Visible);
} else {
vh.FooterLayout.setVisibility(View.Gone);
}
And for example - from activity I simply redraw needed item:
_postListAdapter.notifyItemChanged(position)// if you want show/hide footer - position is amountOfPosts.size() and also change bool variable - amountOfPosts[amountOfPosts.size()].isShown
For the sake of completeness, you should note that setting view visibility to GONE would not hide the margins. You need to do something like this :
if(itemView.getVisibility() != GONE) itemView.setVisibility(GONE);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
layoutParams.setMargins(0, 0, 0, 0);
itemView.setLayoutParams(layoutParams);
I have a CardScrollView with multiple cards. Swiping left and right moves between the cards.
Some of the cards have a lot of content on them. I used a ScrollView so the user can scroll through the card to see the content.
Glass doesn't know whether it should scroll to a different card or scroll on the card it is on when the user swipes their finger for obvious reasons. It chooses to scroll to a different card.
To differentiate, I want to use the GestureDetector to make a one finger scroll scroll cards, and a two finger scroll scroll on the selected card. Seems easy enough, so I made the createGestureDetector() method and put if statements for each case.
Now I have a problem...I do not know how to tell the CardScrollView to advance or go back a card, and I dont know how to make the ScrollBody scroll based on the gesture.
I looked through all of the available methods and nothing stuck out to me as particularly helpful. Does anyone have any idea how to do this?
Bonus question: I saw a lot of "dispatch" commands, like dispatchGenericMotionEvent. What do dispatch methods do?
EDIT:
Here is my code after Jean Vacca's suggestion:
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
if(currentCount == 2){
mCardScrollView.deactivate();
}else{
mCardScrollView.activate();
}
}
});
return gestureDetector;
}
and the xml for my views is:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ScrollView
android:id="#+id/scrollBody"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">
<LinearLayout
android:id="#+id/scrollLinearLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</ScrollView>
</RelativeLayout>
Which is filled with TextViews in this code segment located in the CardScrollAdapter:
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
int nextID = 3;
if (convertView == null) {
convertView = View.inflate(context, R.layout.my_card, null);
holder = new ViewHolder();
MyClass mine = mMyList.get(position);
LinearLayout ll = (LinearLayout)convertView.findViewById(R.id.scrollLinearLayout);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
holder.name = new TextView(this.context);
holder.name.setId(nextID);
nextID++;
holder.name.setTextSize(50);
holder.name.setText(mine.getName());
holder.name.setLayoutParams(lp);
holder.name.setGravity(Gravity.CENTER);
ll.addView(holder.name);
holder.infoTextViews = new ArrayList<TextView>(mine.getInfo().size());
for(int i = 0; i < mine.getInfo().size(); i++)
{
holder.infoTextViews.add(new TextView(this.context));
TextView tv = holder.infoTextViews.get(i);
tv.setId(nextID);
nextID++;
tv.setTextSize(24);
tv.setText(mine.getInfo().get(i));
tv.setLayoutParams(lp);
tv.setGravity(Gravity.CENTER);
ll.addView(tv);
}
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
I hope these edits help!
I had a similar problem on my project. To resolve it, I had to handle the "onFingerCountChanged" in the GestureDetector and desactivate the CardScrollView when i have 2 fingers count. So when I use one finger the cardscrollview scroll normaly and when I use two finger on can scroll in my card using the gestureDetector.
You code should look something like this :
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
if(currentCount == 2){
yourCardScrollView.deactivate();
}else{
yourCardScrollView.activate();
}
}
....
}
EDIT: I notice that my first answer is not work. I have another one.
You can use following code in your Activity.
#Override
public boolean dispatchGenericMotionEvent(MotionEvent ev) {
if (ev.getPointerCount() > 1) {
return true;
}
return super.dispatchGenericMotionEvent(ev);
}
When dispatchGenericMotionEvent actives, detect if pointer is greater than one (muit-touch), return true and consume it.
I tested, but still have bug.
https://code.google.com/p/google-glass-api/issues/detail?id=632
Reply me if it works.