Flip between Views Android - android

I am coding an application that has an activity that can supply the end user with data in two formats a bar graph view using the Teechart api (available here: http://www.steema.com/teechart/mobile) and a listview native in android. Currently I have some logic like so
first i Initialize a boolean flag = true;
I then use this button logic to change between views.
OnClickListener changeViewListener = new OnClickListener(){
public void onClick(View v){
if(!flag){
listLayout.setVisibility(View.GONE);
chartView.setVisibility(View.VISIBLE);
changeView.setText("List");
flag = true;
}else{
listLayout.setVisibility(View.VISIBLE);
chartView.setVisibility(View.GONE);
changeView.setText("Graph");
flag = false;
}
}
};
This code works great and gives me no trouble, I am just questioning whether this can be done a better way such as using a view flipper? And if so how do I implement the view flipper code to switch between these two views?
Or should I be using fragments for each view? Any help would be much appreciated.

Maybe this could be of help to you:
Animate between Views
It gives a generic example, may be you can tweak it to get the flip effect you want.
Update:
That tutorial also gives links to various Animation docs. From that, I think you can use Rotate Animation to create the flip effect. You can give the angle of rotation and the pivot about which to rotate the view.
The concept is that you rotate one view out and rotate in the other view.
Update:
View Flipper is an implementation of Animating between views. The above method I posted was generic, you can toy around with values and create animations with you having much more finer control. You can create transitions between Views that others may never have tried.
Steps for View Flipper:
1. In View Flipper, you define a Flipper element in your Layout XML file. To this flipper element, you add two child elements, which could simply be two Views OR two Layouts OR one View and one Layout. The View Flipper flips between these two Views you have defined.
2. Once you have created this much in XML, you then create four animation rules under /res/anim for the following types of entry and exit transitions:
a. Left In
b. Left Out
c. Right In
d. Right Out
3. After 1 and 2, you now add Touch or Gesture listeners in your code, to listen for Touch and Listen events. Inside these listeners, you then initiate the animation using vf.setInAnimation() or vf.setOutAnimation(), where vf is your ViewFlipper instance.
You can find complete code over here:
1. View Flipper Tutorial 1
2. View Flipper Tutorial 2
Update:
A few tweaks have to be made to make View Flipper work with ListView. I found this other SO question where the same problem was solved with a minor edit. Check it out here.

If you only have two views that you want to switch between, this approach is good enough. However, you can use a view pager to implement this Such an approach would particularly be useful if you have several views so that you don't render them all at once and waste memory. ViewPager will manage when to create and destroy views.
Define in layout
<android.support.v4.view.ViewPager
android:id="#+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Create an adapter
class MyPagerAdapter extends PagerAdapter {
public int getCount() {
return 2;
}
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
// Inflate the correct view based on position
View view = inflater.inflate(R.layout.yourLayoutHere, null);
// ... Setup the view
((ViewPager) collection).addView(view, 0);
return view;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
}
Set the adapter
ViewPager viewPager = findViewById(R.id.viewPager);
viewPager.setAdapter(new MyPagerAdapter());
Now on button click, you can set the current item of view pager.
viewPager.setCurrentItem(position);

Related

PagerAdapter returns wrong position for Multi View Pager

I am implementing caurosel like view pager by adjusting page margin. I am able to implement like below
but i am facing problem with PagerAdapter
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view= inflater.inflate(R.layout.mylayout, null);
//
Button btn=(Button)view.findViewById(R.id.button1);
btn.setTag(position);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("position",v.getTag()+"");
}
}
return imgView;
}
Though I am setting Tags, I am able to get correct position only for center page (Selected item), but when I click on left side page's button it returns wrong value.
I have searched about this issue lot, I could not find the solution so far.
looking for your help.
Thanks
You can use RecyclerView
LinearLayoutManager layoutManager = ...
recyclerView.setLayoutManager(layoutManager);
//when you want horizontal
layoutManager.setOrientation(context,LinearLayoutManager.HORIZONTAL,false);
//when you want vertical
layoutManager.setOrientation(context,LinearLayoutManager.VERTICAL,false);
There was no issues with PagerAdapter. Actual issue was due to a third party library which i used as wrapper to animate the views.

Gallery: Effect in item selected

I need to have an scroll with items together, and the selected item should expand a part down.
I am currently using a Gallery (I tried with viewflow and viewpager, but the items have much space between them), but I need to know how can I do this effect.
I have 2 ideas, but i don't know how can I implement it.
1) The expandable part is a LinearLayout with visibility=gone, and when the item is selected, this layout should be visible. (Gallery do not have "onItemSelectedListener")
2) Treat each element as a fragment (once I use a Viewpager that use this, https://github.com/mrleolink/SimpleInfiniteCarousel)
It does not necessarily have to be a gallery, any idea is welcome
I am working on an Activity.
Depends on the behavior that you want. Some questions can more than one item be expanded at a time? Do you want the views to be paged (snap into place) or smooth scroll them?
One Suggestion I have is to make a custom view for the individual cells. Then add them programmatically to a HorizontalScrollView Object.
HorizontalScrollView hsv = new HorizontalScrollView(activity);
LinearLayout hll = new LinearLayout(activity);
hll.setOrientation(LinearLayout.HORIZONTAL);
for(int i=0;i<items.length();i++){
hsv.addView(new CustomExpandView(item));
}
The CustomExpandView would be used for your cells and could be something like this...
public class CustomExpandView extends RelativeLayout implements OnClickListener {
MyActivity mActivity = null;
ImageView ivImage, ivOverImage;
RelativeLayout rlView;
public CustomExpandView(Context context) {
super(context);
initialize();
}
public CustomExpandView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
public void initialize() {
mActivity = (MyActivity) this.getContext();
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.custom_cell_expand, this, true);
//you can initialize subviews here
rlView = (RelativeLayout) getChildAt(0);
ivImage = (ImageView) rlView.getChildAt(0);
ivOverImage = (ImageView) rlView.getChildAt(1);
rlView.setOnFocusChangeListener(new OnFocusChangeListener(){
#Override
public void onFocusChange(View v, boolean hasFocus) {
LinearLayout expand = v.findViewById(R.id.view_i_want_to_expand);
if(hasFocus)
expand.setVisibility(View.VISIBLE);
else
expand.setVisibility(View.GONE);
}
});
}
You gave the answer yourself. You can use a ViewPager, with fragments, and have an animation to extend the lower part of the window. Depends on whether you want the windows to be full screen or not. A viewpager doesn't necessarily need fragments, you can use ordinary views, and an appropriate adapter. Just play with it and see which solution you like most.
Next time, just create the code and the app, and ask a much more specific question, with code to illustrate the issue you're experiencing.
You could simply define a TableView with just one TableRow (or as many as you need) and set a onClickListener for each of those Views inside the TableRow, which would make that on any click, the selected View would expand itself.
I don't know whether you'll have a static number of Views inside that row or you'll construct them dynamically, but this should work for any of them, the real "work" here about populating that row.
Once you have your row of Views, simply declare an onClickListener() on each of them. For example, this should be enough:
OnClickListener myListener = new OnClickListener() {
#Override
public void onClick(final View v) {
v.setVisibility(View.VISIBLE);
}
};
And as the onClick event for all of your items inside the TableRow:
for (View v : myTableRowViews)
v.setOnClickListener(myListener);
This has a disadvantage: You can know which View has been clicked for selection, but natively you cannot know which has been deselected, so you'll need to keep track of the last selected tab declaring a class-wide variable and setting it each time onClick() is fired, so your listener will become something like this:
// In your class declare a variable like this
View lastSelected = null;
OnClickListener myListener = new OnClickListener() {
#Override
public void onClick(final View v) {
if (lastSelected != null)
lastSelected.setVisibility(View.GONE);
v.setVisibility(View.VISIBLE);
lastSelected = v;
}
};
Additionally, you can set an animation to the effect to make it more attractive, but mainly this is the idea.
One last thing: To make it work this way you'll need to set the layout_height of both your TableRow and the View items inside, so it may expand afterwards when you set the additional part as visible. Also, to make it look good all of your Views will have to be the same height (both in the reduced and extended state).

Creating Grid of images or custom buttons that are clickable

So I have been trying to use a canvas with bitmaps to create a grid of clickable images for a game. It is made to be a 19 x 19 board and this would be made of clickable images so that when you click a image it changes to a new image. I have tried doing this and I get the grid of images but I can not figure out a way to make them clickable. I would show code but there is nothing to show really. its just a basic custom view. Maybe I am doing this all wrong but I have seen a way that is somewhat similar that works but it does not use custom images. I can add a onTouchListener and then I get a response back but it still does not fulfill what I am trying to accomplish. I guess I need to create buttons inside of my custom view but I need the buttons to be customized by images and I cant figure out how I would go about doing that. That is where the issue lies, If there is a way to create a custom View of a grid of customizable buttons. How would I go about doing that? Sorry if this question seems.... messy but I have been working at this for awhile now and am getting pretty confused and lost. Any help is appreciated at this point.
Yep, I think so. Not sure but if you use a grid view with image views on them you can do what you want to accomplish. For more in formation, check here:
http://developer.android.com/guide/topics/ui/layout/gridview.html
http://developer.android.com/reference/android/widget/ImageView.html
You could just use a GridFragment and just implement the onGridItemClick method to handle the clicks. It is pretty straight forward.
If you want to have a gridview with buttons with custom background images I would go about it something like this.
I would store all my drawables in an int array
int[] imageResource = new int[] {R.drawable.icon, R.drawable.icon2, R.drawable.icon3};
Set your gridView with the adapter shown below and pass your drawables stored in an array
yourGridView.setAdapter(new GridAdapter(imageResource));
Now for the actual inner class Adapter
//create your own custom adapter for your gridView
public class GridAdapter extends BaseAdapter {
int[] gridImages;
public GridAdapter(int images[]){
gridImages = images;
}
#Override
public View getView(final int position, View convertView,
ViewGroup parent) {
LayoutInflater li = context.getLayoutInflater();
if (convertView == null) {
//here you inflate your xml containing a button.
convertView = li.inflate(R.layout.grid_item, null);
}
//you reference the button contained in the inflated xml
Button imageButton = (Button) convertView.findViewById(R.id.grid_button);
//now you set the button with a drawable from your int array
Drawable image = getResources().getDrawable(gridImages[position);
// Now simply add your onClickListener and whatever else you need to achieve
//return your view
return convertView;
}
public int getCount() {
return gridImages.length;
}
public Object getItem(int position) {
return gridImages[position];
}
public long getItemId(int position) {
return position;
}
}
If done correctly, this should cycle through all your drawables referenced in the int array and place them on to buttons.

ViewPager does not redraw content, remains/turns blank

We're suffering from a very strange issue with ViewPager here. We embed lists on each ViewPager page, and trigger notifyDataSetChanged both on the list adapter and the view pager adapter when updating list data.
What we observe is that sometimes, the page does not update its view tree, i.e. remains blank, or sometimes even disappears when paging to it. When paging back and forth a few times, the content will suddenly reappear. It seems as if Android is missing a view update here. I also noticed that when debugging with hierarchy viewer, selecting a view will always make it reappear, apparently because hierarchy viewer forces the selected view to redraw itself.
I could not make this work programmatically though; invalidating the list view, or the entire view pager even, had no effect.
This is with the compatibility-v4_r7 library. I also tried to use the latest revision, since it claims to fix many issues related to view pager, but it made matters even worse (for instance, gestures were broken so that it wouldn't let me page through all pages anymore sometimes.)
Is anyone else running into these issues, too, or do you have an idea of what could be causing this?
If the ViewPager is set inside a Fragment with a FragmentPagerAdapter, use getChildFragmentManager() instead of getSupportFragmentManager() as the parameter to initialize your FragmentPagerAdapter.
mAdapter = new MyFragmentPagerAdapter(getChildFragmentManager());
Instead of
mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
We finally managed to find a solution. Apparently our implementation suffered of two issues:
our adapter did not remove the view in destroyItem().
we were caching views so that we'd have to inflate our layout just once, and, since we were not removing the view in destroyItem(), we were not adding it in instantiateItem() but just returning the cached view corresponding to the current position.
I haven't looked too deeply in the source code of the ViewPager - and it's not exactly explicit that you have to do that - but the docs says :
destroyItem()Remove a page for the given position. The adapter is responsible for removing the view from its container, although it only must ensure this is done by the time it returns from finishUpdate(ViewGroup).
and:
A very simple PagerAdapter may choose to use the page Views themselves as key objects, returning them from instantiateItem(ViewGroup, int) after creation and adding them to the parent ViewGroup. A matching destroyItem(ViewGroup, int, Object) implementation would remove the View from the parent ViewGroup and isViewFromObject(View, Object) could be implemented as return view == object;.
So my conclusion is that ViewPager relies on its underlying adapter to explicitly add/remove its children in instantiateItem()/destroyItem(). That is, if your adapter is a subclass of PagerAdapter, your subclass must implement this logic.
Side note: be aware of this if you use lists inside ViewPager.
I had the exact same problem but I actually destroyed the view in destroyItem (I thought). The problem however was that I destroyed it using viewPager.removeViewAt(index); insted of viewPager.removeView((View) object);
Wrong:
#Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeViewAt(position);
}
Right:
#Override
public void destroyItem(ViewGroup viewPager, int position, Object object) {
viewPager.removeView((View) object);
}
ViewPager tries to do clever stuff around re-using items, but it requires you to return new item positions when things have changed. Try adding this to your PagerAdapter:
public int getItemPosition (Object object) { return POSITION_NONE; }
It basically tells ViewPager that everything has changed (and forces it to re-instantiate everything). That's the only thing I can think of off the top of my head.
Tried too many solutions but unexpectedly viewPager.post() worked
mAdapter = new NewsVPAdapter(getContext(), articles);
viewPager.post(new Runnable() {
#Override
public void run() {
viewPager.setAdapter(mAdapter);
}
});
The Android Support Library has a demo Activity that includes a ViewPager with a ListView on every page. You should probably have a look and see what it does.
In Eclipse (with Android Dev Tools r20):
Select New > Android Sample Project
Select your target API level (I suggest the newest available)
Select Support4Demos
Right-click the project and select Android Tools > Add Support Library
Run the app and select Fragment and then Pager
The code for this is in src/com.example.android.supportv4.app/FragmentPagerSupport.java. Good luck!
I ran into this and had very similar issues. I even asked it on stack overflow.
For me, in the parent of the parent of my view someone subclassed LinearLayout and overrode requestLayout() without calling super.requestLayout(). This prevented onMeasure and onLayout from being called on my ViewPager (although hierarchyviewer manually calls these). Without being measured they'll show up as blank in ViewPager.
So check your containing views. Make sure they subclass from View and don't blindly override requestLayout or anything similar.
Had the same issue, which is something to do with ListView (because my empty view shows up fine if the list is empty). I just called requestLayout() on the problematic ListView. Now it draws fine!
I ran into this same problem when using a ViewPager and FragmentStatePagerAdapter. I tried using a handler with a 3 second delay to call invalidate() and requestLayout() but it didn't work. What did work was resetting the viewPager's background color as follows:
MyFragment.java
private Handler mHandler;
private Runnable mBugUpdater;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = new ViewPager(getActivity());
//...Create your adapter and set it here...
mHandler = new Handler();
mBugUpdater = new Runnable(){
#Override
public void run() {
mVp.setBackgroundColor(mItem.getBackgroundColor());
mHandler = null;
mBugUpdater = null;
}
};
mHandler.postDelayed(mBugUpdater,50);
return rootView;
}
#Override
public void onPause() {
if(mHandler != null){
//Remove the callback if it hasn't triggered yet
mHandler.removeCallbacks(mBugUpdater);
mHandler = null;
mBugUpdater = null;
}
super.onPause();
}
I had a problem with the same symptoms, but a different cause that turned out to be a silly mistake on my part. Thought I'd add it here in case it helps anyone.
I had a ViewPager using FragmentStatePagerAdapter which used to have two fragments, but I later added a third. However, I forgot that the default off screen page limit is 1 -- so, when I'd switch to the new third fragment, the first one would get destroyed, then recreated after switching back. The problem was that my activity was in charge of notifying these fragments to initialize their UI state. This happened to work when the activity and fragment lifecycles were the same, but to fix it I had to change the fragments to initialize their own UI during their startup lifecycle. In the end I also wound up changing setOffscreenPageLimit to 2 so that all three fragments were kept alive at all times (safe in this case since they were not very memory intensive).
I had similar issue. I cache views because I need only 3 views in ViewPager. When I slide forward everything is okay but when I start to slide backward occurs error, it says that "my view already has a parent". The solution is to delete unneeded items manually.
#Override
public Object instantiateItem(ViewGroup container, int position) {
int localPos = position % SIZE;
TouchImageView view;
if (touchImageViews[localPos] != null) {
view = touchImageViews[localPos];
} else {
view = new TouchImageView(container.getContext());
view.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
touchImageViews[localPos] = view;
}
view.setImageDrawable(mDataModel.getPhoto(position));
Log.i(IRViewPagerAdpt.class.toString(), "Add view " + view.toString() + " at pos: " + position + " " + localPos);
if (view.getParent() == null) {
((ViewPager) container).addView(view);
}
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object view) {
// ((ViewPager) container).removeView((View) view);
Log.i(IRViewPagerAdpt.class.toString(), "remove view " + view.toString() + " at pos: " + position);
}
..................
private static final int SIZE = 3;
private TouchImageView[] touchImageViews = new TouchImageView[SIZE];
For me the problem was coming back to the activity after the app process was killed. I am using a custom view pager adapter modified from the Android sources.The view pager is embedded directly in the activity.
Calling viewPager.setCurrentItem(position, true);
(with animation) after setting the data and notifyDataSetChanged() seems to work, but if the parameter is set to false it doesn't and the fragment is blank. This is an edge case which may be of help to someone.
For Kotlin users:
In your fragments;
Use childFragmentManager instead of viewPagerAdapter

Create a ViewPager or equivalent WITH functionality in Android

I know this may sound like a terrible question to ask but I have been researching as much as I could to figure this out. I have an application that requires a view pager to scroll horizontally to display different views. Within each view, it needs functionality, for one view it could be just pressing a button, another view is required to download data from a server (for example, retrieving the latest Twitter feed) as well as other functionality. The main point is that within the View Pager, each view requires functionality.
My original idea was to follow this tutorial:
http://mobile.tutsplus.com/tutorials/android/android-user-interface-design-horizontal-view-paging/
However, this is just providing views which have no interaction. I have managed to implement this and add my layouts, however this is only solving half of the problem. It shows how to add basic operations within a comment such as a single button. I want each view to have its own activity which is capable of doing its own unique thing.
Here is what I originally had:
public class DashboardContainerActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//Set content view to the dashboard container xml view
setContentView(R.layout.dashboard_container);
//Create a new instance of my page adapter from below
MyPageAdapter adapter = new MyPageAdapter();
//Reference the view pager used in the dashboard container xml view
ViewPager myPager = (ViewPager) findViewById(R.id.dashboardpanelpager);
//set an adapter to the view pager
myPager.setAdapter(adapter);
//First panel to be shown when opened
myPager.setCurrentItem(3);
}
}
/*------------------------------------------------------*/
class MyPageAdapter extends PagerAdapter {
public int getCount() {
//Return 7 as there will be 7 panes in the dashboard
return 7;
}
public Object instantiateItem(View collection, int position) {
LayoutInflater inflater = (LayoutInflater) collection.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = null;
switch (position) {
case 0:
v = inflater.inflate(R.layout.dashboard_social, null);
break;
case 1:
v = inflater.inflate(R.layout.dashboard_info, null);
//DISPLAY INFORMATION FROM SERVER AND DISPLAY HERE
break;
case 2:
v = inflater.inflate(R.layout.dashboard_allcourses, null);
//LIST OF COURSES
break;
case 3:
v = inflater.inflate(R.layout.dashboard_news, null);
//USE HTTP HERE FOR TWITTER FEED
break;
case 4:
v = inflater.inflate(R.layout.dashboard_mycourse, null);
//DOWNLOAD USER'S PERSONAL INFORMATION AND DISPLAY HERE
break;
case 5:
v = inflater.inflate(R.layout.dashboard_media, null);
//DISPLAY LATEST UPLOADED MULTIMEDIA
break;
case 6:
v = inflater.inflate(R.layout.dashboard_extras, null);
break;
}
((ViewPager) collection).addView(v, 0);
return v;
}
#Override
public void destroyItem(View arg0, int arg1, Object arg2) {
((ViewPager) arg0).removeView((View) arg2);
}
#Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == ((View) arg1);
}
#Override
public Parcelable saveState() {
return null;
}
}
I have separate activities for each layout added to the ViewPager but I am guessing that these activities cannot be added into the ViewPager instead of just the layouts.
I have read something about fragments, but I am not sure whether that's compatible with API level 8, apparently this is targeted at Honeycomb and Ice Cream Sandwich.
It's not possible to have an Activity as part of a ViewPager, however there is no reason why you can't add the functionality you describe to each page in your ViewPager. To assign interaction or events to components in each view just add the correct listeners in instantiateItem() in each case statement:
case 0:
v = inflater.inflate(R.layout.dashboard_social, null);
Button myButton = (Button) v.findViewById(R.id.name_of_button_in_social_dashboard);
myButton.setOnClickListener(...);
break;
For any other interactions, like getting the http requests for the twitter feed, just execute those as part of your main activity (something like http requests should be done in a background thread of course). When you want to update the UI in the twitter page, just use ViewPager.getChildAt(3) to fetch the child element. Think of your Activity as just a big layout with 7 children views that are all available at once (but the user will only see them as they swipe).
With all that said, a better design patter might be to use Fragments with a FragmentPagerAdapter backing your ViewPager. This allows better logical breakdown of the various pages into different classes - Fragments also provide other uses like being able to load multiple on-screen at once for larger screen layouts (tablets).
Like ViewPager, Fragments are available all the way back to API Level 4 via the support library (see Fragment). So you don't need to worry about backward compatibility.

Categories

Resources