PigeonholeView

Grid-based reorderable view like Android home screen

License

License

Categories

Categories

Net Geo Business Logic Libraries Geospatial
GroupId

GroupId

net.kyu_mu
ArtifactId

ArtifactId

pigeonholeview
Last Version

Last Version

1.0.4
Release Date

Release Date

Type

Type

aar
Description

Description

PigeonholeView
Grid-based reorderable view like Android home screen
Project URL

Project URL

https://github.com/iizukanao/PigeonholeView
Source Code Management

Source Code Management

https://github.com/iizukanao/PigeonholeView

Download pigeonholeview

How to add to project

<!-- https://jarcasting.com/artifacts/net.kyu_mu/pigeonholeview/ -->
<dependency>
    <groupId>net.kyu_mu</groupId>
    <artifactId>pigeonholeview</artifactId>
    <version>1.0.4</version>
    <type>aar</type>
</dependency>
// https://jarcasting.com/artifacts/net.kyu_mu/pigeonholeview/
implementation 'net.kyu_mu:pigeonholeview:1.0.4'
// https://jarcasting.com/artifacts/net.kyu_mu/pigeonholeview/
implementation ("net.kyu_mu:pigeonholeview:1.0.4")
'net.kyu_mu:pigeonholeview:aar:1.0.4'
<dependency org="net.kyu_mu" name="pigeonholeview" rev="1.0.4">
  <artifact name="pigeonholeview" type="aar" />
</dependency>
@Grapes(
@Grab(group='net.kyu_mu', module='pigeonholeview', version='1.0.4')
)
libraryDependencies += "net.kyu_mu" % "pigeonholeview" % "1.0.4"
[net.kyu_mu/pigeonholeview "1.0.4"]

Dependencies

There are no dependencies for this project. It is a standalone project that does not depend on any other jars.

Project Modules

There are no modules declared in this project.

Grid-based reorderable view like Android home screen

Screenshot Edit mode

Download

If you are using Android Studio, add the following line to the dependencies section in your module-level build.gradle.

implementation 'net.kyu_mu:pigeonholeview:1.0.4'

Usage

An example app is available at app directory. To run the example app, open this top-level directory in Android Studio and press the "Run" button.

The instructions below are a complete guide to integrate PigeonholeView in your app.

First, define a class that holds the data for a single cell. Include an int instance variable which stores a view position in PigeonholeView.

MyData.java:

/**
 * Data for a single cell.
 */
public class MyData {
    private String name;
    private int imageResourceId;
    private int viewPosition; // view position in PigeonholeView

    public MyData(String name, int imageResourceId, int viewPosition) {
        this.name = name;
        this.imageResourceId = imageResourceId;
        this.viewPosition = viewPosition;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getImageResourceId() {
        return imageResourceId;
    }

    public void setImageResourceId(int imageResourceId) {
        this.imageResourceId = imageResourceId;
    }

    public int getViewPosition() {
        return viewPosition;
    }

    public void setViewPosition(int viewPosition) {
        this.viewPosition = viewPosition;
    }
}

Then, create an Activity that contains PigeonholeView. In the example below, all parameters prefixed with custom: are optional. In order to use custom: attributes, you have to add xmlns:custom="http://schemas.android.com/apk/res-auto" to the root element. For details of the attributes, see XML Attributes.

activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <net.kyu_mu.pigeonholeview.PigeonholeView
        android:id="@+id/my_pigeonhole_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        custom:cellHeight="88dp"
        custom:cellWidth="80dp"
        custom:dragStartAnimationDuration="100"
        custom:dropAreaText="Drop here to edit"
        custom:dropAreaTopPadding="10dp"
        custom:editable="true"
        custom:topSpaceHeight="?attr/actionBarSize" />

</RelativeLayout>

Include v7 appcompat Android Support Library in module-level build.gradle.

dependencies {
    compile 'net.kyu_mu:pigeonholeview:1.0.4'
    compile "com.android.support:appcompat-v7:27.1.1"
}

Edit values/styles.xml and add a custom style (CustomActionBarTheme) that enables ActionBar overlay:

<resources xmlns:tools="http://schemas.android.com/tools">

    <style name="CustomActionBarTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
        <item name="android:windowActionBarOverlay" tools:ignore="NewApi">true</item>
        <!-- Support library compatibility -->
        <item name="windowActionBarOverlay">true</item>
    </style>

</resources>

Edit AndroidManifest.xml and apply CustomActionBarTheme to the Activity using android:theme attribute.

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:theme="@style/CustomActionBarTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Set up the view in the code.

MainActivity.java:

public class MainActivity extends AppCompatActivity implements
        PigeonholeView.PigeonholeViewListener<MyData> {

    private PigeonholeView<MyData> pigeonholeView;
    private ArrayList<MyData> myDataList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Test data
        myDataList = new ArrayList<>();
        myDataList.add(new MyData("Button 1", android.R.drawable.ic_menu_myplaces, 0));
        myDataList.add(new MyData("Button 2", android.R.drawable.ic_menu_rotate, 1));
        myDataList.add(new MyData("Button 3", android.R.drawable.ic_menu_mapmode, 2));

        pigeonholeView = (PigeonholeView<MyData>) findViewById(R.id.my_pigeonhole_view);

        // This is the bridge between PigeonholeView and your data
        pigeonholeView.setDataProvider(new PigeonholeView.DataProvider<MyData>() {
            /**
             * Return the view position for the item.
             */
            @Override
            public int getViewPosition(MyData item) {
                return item.getViewPosition();
            }

            /**
             * Store the view position for the item.
             */
            @Override
            public void setViewPosition(MyData item, int viewPosition) {
                item.setViewPosition(viewPosition);

                // You don't need to persist the view positions here. Instead,
                // save them in onReorder() to minimize the overhead.
            }

            /**
             * Return the view for the item.
             */
            @Override
            public View getView(View cellView, MyData item) {
                // Reuse the existing view if cellView is not null.
                // Otherwise, instantiate a view.
                if (cellView == null) {
                    LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
                    cellView = inflater.inflate(R.layout.list_item, pigeonholeView, false);
                }

                // Update the image
                ImageView imageView = (ImageView) cellView.findViewById(R.id.item_image);
                imageView.setImageResource(item.getImageResourceId());

                // Update the name
                TextView nameTextView = (TextView) cellView.findViewById(R.id.item_name);
                nameTextView.setText(item.getName());

                return cellView;
            }

            /**
             * Return the iterator for the list of cells.
             */
            @Override
            public Iterator<MyData> iterator() {
                return myDataList.iterator();
            }
        });

        pigeonholeView.setOnCellClickListener(new PigeonholeView.OnCellClickListener<MyData>() {
            @Override
            public void onClick(PigeonholeView.CellData<MyData> cellData) {
                // Retrieve the target data
                MyData myData = cellData.getObject();

                Toast.makeText(MainActivity.this, myData.getName() + " is clicked", Toast.LENGTH_SHORT).show();
            }
        });

        // Receive events from PigeonholeView
        pigeonholeView.setListener(this);
    }

    private void hideActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.hide();
        }
    }

    private void showActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.show();
        }
    }

    /**
     * Called when the dragging has started.
     */
    @Override
    public void onDragStart() {
        hideActionBar();
    }

    /**
     * Called when the dragging has ended.
     */
    @Override
    public void onDragEnd() {
        showActionBar();
    }

    /**
     * Called when the user dropped a button to the drop area.
     */
    @Override
    public void onEditObject(MyData myData) {
        // To update the cell data:
        myData.setName("Updated");
        myData.setImageResourceId(android.R.drawable.ic_menu_edit);
        pigeonholeView.updateEditingObject();

//        // To delete the cell:
//        myDataList.remove(myData);
//        pigeonholeView.deleteEditingObject();

//        // To cancel edit:
//        pigeonholeView.cancelEdit();
    }

    /**
     * Called when reordering has happened in the PigeonholeView.
     */
    @Override
    public void onReorder() {
        // You should persist the view positions here.
    }
}

Put list_item.xml in res/layout. This is the layout for a single cell.

Now you can run your app and see PigeonholeView in action.

Adding a button dynamically

If you call pigeonholeView.addObject() with a MyData instance, smallest-avialable view position will be assigned to it.

MyData newData = new MyData("New Button", android.R.drawable.ic_menu_zoom, 0);
myDataList.add(newData);
pigeonholeView.addObject(newData);

To check whether the PigeonholeView is full:

if (pigeonholeView.isFull()) {
    Toast.makeText(this, "Can't add more buttons", Toast.LENGTH_SHORT).show();
} else {
    // Add a button
}

Changing edit mode

To disable edit mode dynamically:

pigeonholeView.setEditable(false);

To enable edit mode dynamically:

pigeonholeView.setEditable(true);

To disable edit mode in xml, add custom:editable="false" attribute to PigeonholeView element. Edit mode is enabled by default.

XML attributes

Attribute Description Type (default value)
custom:editable If true, long click is enabled boolean (true)
custom:cellWidth Width of a cell dimension (80px)
custom:cellHeight Height of a cell dimension (90px)
custom:topSpaceHeight (See the image below) dimension (0px)
custom:dropAreaTopPadding (See the image below) dimension (20px)
custom:dropAreaText Text for drop area string (@string/drop_area__text)
custom:dragStartAnimationDuration Duration of drag start animation in milliseconds integer (200)

View parameters

License

Copyright 2015 Nao Iizuka

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Versions

Version
1.0.4
1.0.3
1.0.2
1.0.1