Monday, October 14, 2013

InfiniteViewPager 0.4 released

The InfiniteViewPager version 0.4 has been released. It now has an OnInfinitePageChangeListener. You can use it by doing the following:

InfiniteViewPager viewPager = ...;
viewPager.setOnInfinitePageChangeListener(new InfiniteViewPager.OnInfinitePageChangeListener() {
  @Override
  public void onPageScrolled(Object indicator, float positionOffset, int positionOffsetPixels) {
  }

  @Override
  public void onPageSelected(Object indicator) {
  }

  @Override
  public void onPageScrollStateChanged(int state) {
  }
});
In general it is not very different from the regular ViewPager.OnPageChangeListener. The callback methods
onPageSelected(final Object indicator)
and
onPageScrolled(Object indicator, float positionOffset, int positionOffsetPixels)
return the current indicator instead of position.

You can bind it with maven:

        <dependency>
            <groupId>com.thehayro</groupId>
            <artifactId>infiniteviewpager</artifactId>
            <version>0.4</version>
            <type>apklib</type>
        </dependency>
 
The code can be found here. 

Thursday, September 26, 2013

InfiniteViewPager - an infinite paging ViewPager

Hi,

a couple of months ago, I wrote an article about enabling infinite paging with the android ViewPager. In my opinion, the proposed solution was rather simple and hacky, since it only changed the text of each page. However with that approach, I finally found the time to do a custom ViewPager widget that enables the infinite paging feature with simple and complex page layouts rather than changing the text of the EditText widget. Here is a video showing the InfiniteViewPager in action.

Including the InfiniteViewPager

Binding the InfiniteViewPager into your application is not different than binding a regular ViewPager. You include it with your xml layout with the following:


<com.thehayro.view.InfiniteViewPager 
    android:id="@+id/infinite_viewpager"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"/>

Using the adapter

Like the regular ViewPager correspondents with its adapter class, the InfiniteViewPager also has its custom adapter called InfinitePagerAdapter. Before this is explained any further, I would like to give some understanding on how it works and what differs from a regular PagerAdapter implementation.
The main difference between a regular PagerAdapter (as we know) and the InfinitePagerAdapter are the number of pages. When implementing a PagerAdapter, one important method you have to implement is getCount(). With that, you tell the ViewPager how many pages you want. When implementing an InfinitePagerAdapter, setting the maximum number of pages is not necessary. The number of scrolling pages is indefinite. This leads to a certain consequence: how is it possible to differentiate one page from another? The regular ViewPager indicates its pages by its index. Methods like ViewPager.setCurrentItem(int index) help to switch to a certain page. For almost every use case, the page index indication is helpful for a finite space. But what about other indicators? For instance a string, where the indication is the alphabet or a concatenation of characters. How would integer index be mapped on a string datastructure or any other class that does not necessarily implement the Comparable interface? The InfinitePagerAdapter provides a solution to that issue. This is shown in the following code:

public abstract class InfinitePagerAdapter<T> extends PagerAdapter {

    /**
     * Standard constructor.
     * @param initValue the initial indicator value the ViewPager
     * should start with.
     */
    public InfinitePagerAdapter(T initValue);

    /**
     *
     * @return the next indicator.
     */
    public abstract T getNextIndicator();

    /**
     *
     * @return the previous indicator.
     */
    public abstract T getPreviousIndicator();

    /**
     * Instantiates a page.
     * @param indicator the indicator the page should be instantiated with.
     * @return a ViewGroup containing the page layout.
     */
    public abstract ViewGroup instantiateItem(T indicator);
}

The InfinitePagerAdapter gives the possibility to set an indicator type. Since the indicator can be any  datatype, it is necessary to implement the getNextIndicator() and getPreviousIndicator() Methods to define the next and previous indicator. This gives a certain flexibility towards the page indication. A simple implementation of the InfinitePagerAdapter can look like this:


public class MyInfinitePagerAdapter<Integer> extends InfinitePagerAdapter {


    public Integer getNextIndicator() {
        // getCurrentIndicator is a protected method.
        return getCurrentIndicator() + 1;
    }


    public Integer getPreviousIndicator() {
        // getCurrentIndicator is a protected method.
        return getCurrentIndicator() - 1;
    }

    public ViewGroup instantiateItem(Integer indicator) {
        // space for rent
        return null;
    }
}

And instantiate it with something like this:
// 0 is the initial type
MyInfinitePagerAdapter<Integer> myAdapter = new MyInfinitePagerAdapter<Integer>(0);

Restoring states on device rotation

The above listed code is the minimum required implementations a developer has to provide in order to use the InfiniteViewPager. However, this has a certain limitation: rotating the device shows the initial page and the current page is lost, due to android's layout reinitialization. This can be solved by furthermore overriding two methods:

String getStringRepresentation(final T currentIndicator);


T convertToIndicator(final String representation);


The first method converts the current indicator into a string representation, and the second does the opposite. These methods provide the InfiniteViewPager to restore its state when the device is rotated.

Binding in your project

You can bind the InfiniteViewPager with maven:

        <dependency>
            <groupId>com.thehayro</groupId>
            <artifactId>infiniteviewpager</artifactId>
            <version>0.3</version>
            <type>apklib</type>
        </dependency>

The code can be found here.

Sunday, July 28, 2013

SeesawView - a visual feedback for flat view interaction

Introduction

Touchscreens enable the direct pointing on the screen contents but also take away the haptic feedback of a keyboard or telephone keypad (if it is a smartphone). On smartphones, a common solution is to give a vibrotactile and (a more than desktop computers) visual feedback when users interact with the user interface. For example a button has different states (pressed, released, disabled etc.). With that information the smartphone user interface gives us the visual (and sometimes haptic) feedback that the user interface component (e.g. button) has been interacted with (see figure 1).
Figure 1: A button that gets interacted with and its visual feedback.

However there are components (e.g. images) that do not have states to indicate the visual feedback when interacting with them (e.g. pressing). I call these components flat components, because the do not have a visual "depth" in comparison of the button. A button implements a to-be-pressed metaphor, whereas an image does not. But there are use cases when an image should be interacted with. Examples are zooming, showing in full screen etc. 
This post introduces an android view container that gives visual feedback for these described flat views. 

SeesawView

The SeesawView a simple view container that seesaws a containing view. Here is a simple video showing the seesawView in action.


The code can be downloaded here.

Sidenote: The view only works properly when the childview has an actual interaction set (e.g. setOnClickListener())

cheers

Tuesday, June 25, 2013

Android: The usability papercut of the paste popup

Introduction

Since Android gingerbread (v. 2.3), Google enhanced the copy/paste functionality by pressing and holding a selected word to copy text to the clipboard[1]. In more recent Android versions the copy and paste functionality is shown in a popup window rather than a context menu as known in gingerbread.

This post is about the definition of an usability papercut that concerns the paste popup window. It is divided into two sections. In the first section I will describe a scenario and in the second section I will talk and discuss about the papercut itself.

Scenario

To illustrate the problem, I wrote a simple application that shows an EditText widget with some entered text as seen in Figure 1.

Figure 1: EditText with entered sample text.


To let the paste popup appear, one just do a press hold on the text. This triggers two operations: a) the placement of the caret and b) the appearance of the popup. In figure 2 it is shown that the popup window is located right above the caret and the press position (white circle).

Figure 2: Appearance of the paste/replace popup.

The papercut

The papercut happens when there is no text in the EditText widget. As seen in figure 3 the touch-hold position and the popup window are "dislocated" in comparison to figure 2.

Figure 3: The papercut in action.

To argue against this dislocation, one can say that the location of the popup follows the law of proximity, which says that "things that are close together as seen as belonging together"[2]. As seen in figure 2 and 3 the paste (and replace) popup appears right above the caret indicating the user that there is a possibility to paste (or replace) some text right where the caret is positioned. However in figure 3 the paste popup appears at an unexpected location, so that one has to visually search for the popup window. The solution I am proposing is to place the popup window right above the pressed hold position of the finger when there is no entered text.

To justify the argument of dislocation, I tried to apply FFitt's Law[2] (an expansion of Fitt's law for finger touch input) and to calculate the mean time to complete the paste task with and without entered text. However this was not possible, because the popup window is not available in the android view hierarchy of the sample app as seen in figure 4.

Figure 4: View hierarchy of the sample app. The red frame highligts the curent view of the sample app. The paste popup is not part of the view hierarchy.




The paste functionality is located in the TextView class (from which the EditText class inherits). In detail, the paste function and management of positioning the caret etc. is outsourced into the Editor class. This class uses internal android classes (e.g. classes that are located in the com.android.internal.* package), which makes it even more difficult to change the popup location as suggested above.

Conclusion

In this post I introduced an usability papercut concerning the paste popup. I wrote a simple application that illustrates the problem. Moreover did I discuss why and how this is a papercut with a suggestion on how to fix it. An attempt on how fix this in code has been introduced as well. I found out that a popup window cannot be captured with the hierarchyviewer, since it is not a part of the view tree. It would be interesting to see a user interface component that is like the popup window but also part of the view hierarchy.

References

[1] Android Gingerbread Platform Hightlights. Available: http://developer.android.com/about/versions/android-2.3-highlights.html. Last accessed 25th June 2013.
[2] Bi, Xiaojun and Li, Yang and Zhai, Shumin. (2013). FFitts law: modeling finger touch with fitts' law. Proceedings of the SIGCHI Conference on Human Factors in Computing Systems. CHI '13 , 1363-1372.
[3] Boeree, George. (2009). Perception and Interaction. Available: http://webspace.ship.edu/cgboer/genpsyperception.html. Last accessed 25th June 2013.