Categoryxml layout

Android Phone EditBox with validation and country flag

I haven’t found any good code snippet for Phone EditBox with nice country flags and validation. So I created my own version.

What I am talking about:

Continue reading

Foursquare like map animation (sliding panel) with ListView

If you are wondering how to achieve map and listview behaviour like in Foursquare – this post is for you.
Here’s a short video what I’m talking about:

Continue reading

Honeycomb GMail animation mystery

There are a lot of questions on the Internet like these:

http://stackoverflow.com/questions/4817900/android-fragments-and-animation
http://stackoverflow.com/questions/5327636/animating-fragments-and-the-back-stack

GMail Honeycomb Android slide animation

If you are looking for a sample code – this post is for you.

Everybody wants to implement slide-in/slide-out animations like in GMail Tablet client. They try to use fragment animations (setCustomAnimations for FragmentTransaction). But if you take a deep look into GMail client implementation – they use LinearLayout and ObjectAnimator.

The code is quite simple – you just change left margin of the root view + change width of the right view.

package com.fragment.test;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;

public class FragmentAnimationTestActivity extends Activity implements Fragment2.FragmentResultListener {

    private static final TimeInterpolator sCollapseInterpolator = new DecelerateInterpolator(2.5F);

    private View mPanel1;
    private View mPanel2;
    private View mLayout;

    boolean isCollapsed;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mLayout = findViewById(R.id.l1);
        mPanel1 = findViewById(R.id.fragment1);
        mPanel2 = findViewById(R.id.fragment2);
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(R.id.fragment1, Fragment1.newInstance(), "f1");
        ft.replace(R.id.fragment2, Fragment2.newInstance(this), "f2");
        ft.commit();
    }

    public int getPanelLeft() {
        return ((ViewGroup.MarginLayoutParams) mLayout.getLayoutParams()).leftMargin;
    }

    public void setPanelLeft(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mLayout.getLayoutParams();
        lp.leftMargin = paramInt;
        mLayout.setLayoutParams(lp);
    }

    public int getPanel2W() {
        return ((ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams()).width;
    }

    public void setPanel2W(int paramInt) {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams();
        lp.width = paramInt;
        mPanel2.setLayoutParams(lp);
    }

    @Override
    public void onBtnClick() {
        if (isCollapsed) {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", -300, 0);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 1280, 980);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        } else {
            PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
            arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", 0, -300);
            arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 980, 1280);
            ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
                    arrayOfPropertyValuesHolder).setDuration(400);
            localObjectAnimator.setInterpolator(sCollapseInterpolator);
            localObjectAnimator.start();
        }
        isCollapsed = !isCollapsed;
    }

}

Of course, you can calculate all values dynamically. This is just a quick ugly sample. Full source code is available here.

Happy tabletting! 🙂

//DL

Horizontal slide gallery with pages

Imagine you want to create interactive horizontal slide gallery with paging (scroll left/right not one-by-one but pages).
Like this one:

Hopefully you can easily implement this with HorizontalScrollView. Since API level 3 it has method smoothScrollBy.

Your code may looks like:

public class TestUIActivity extends Activity {

	private GestureDetector gestureDetector = null;
	private HorizontalScrollView hs;

	private int mWidth = 1160;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		gestureDetector = new GestureDetector(new MyGestureDetector());
		hs = (HorizontalScrollView) findViewById(R.id.hs);
		hs.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (gestureDetector.onTouchEvent(event)) {
					return true;
				}
				if (event.getAction() == 1) {
					if (hs.getScrollX() > mWidth + mWidth / 2) {
						hs.smoothScrollBy(mWidth * 2 - hs.getScrollX(), 0);
					} else if (hs.getScrollX() > mWidth / 2) {
						hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
					} else {
						hs.smoothScrollBy(-hs.getScrollX(), 0);
					}
					return true;
				}
				return false;
			}
		});
	}

	class MyGestureDetector extends SimpleOnGestureListener {

		@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY) {
			if (e1.getX() < e2.getX()) {
				moveLeft();
			} else {
				moveRight();
			}
			return true;
		}
	}

	private void moveRight() {
		if (hs.getScrollX() > 0 && hs.getScrollX() < mWidth) {
			hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
		} else if (hs.getScrollX() > mWidth && hs.getScrollX() < mWidth * 2) {
			hs.smoothScrollBy(mWidth * 2 - hs.getScrollX(), 0);
		}

	}

	private void moveLeft() {
		if (hs.getScrollX() > 0 && hs.getScrollX() < mWidth) {
			hs.smoothScrollBy(-hs.getScrollX(), 0);
		} else if (hs.getScrollX() > mWidth && hs.getScrollX() < mWidth * 2) {
			hs.smoothScrollBy(mWidth - hs.getScrollX(), 0);
		}

	}
}

and simple layout that you may construct from code:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<com.dlukashev.test.HorizontalScrollView
		android:id="@+id/hs"
		android:scrollbars="none"
		android:layout_width="1160dp"
		android:layout_height="wrap_content">
		<LinearLayout
			android:layout_width="wrap_content"
			android:layout_height="fill_parent">
			<!-- page1 -->
			<TextView
				android:id="@+id/id1"
				android:background="#FFFFFF"
				android:layout_marginLeft="10dp"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFFFF"
				android:layout_marginRight="20dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<!-- page2 -->
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FF0000"
				android:layout_marginRight="20dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<!-- page3 -->
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
			<TextView
				android:background="#FFFF00"
				android:layout_marginRight="10dp"
				android:layout_width="220dp"
				android:layout_height="220dp" />
		</LinearLayout>
	</com.dlukashev.test.HorizontalScrollView>
</LinearLayout>

One sad detail that you cannot change view animation speed (DEFAULT_DURATION=250 in class OverScroller). But you can easily fix it by adding HorizontalScrollView, OverScroller, Scroller and EdgeGlow to your project.

You can find full sample with animation speed = 500 here. This sample is for tablet resolution – change layout and items sizes for the phone if you would like.

//DL

long or notlong

As you know you can name layout or resource folders with “-long” or “-notlong” postfix.
Documentation says:

  1. long – resources for screens of any size or density that have a significantly taller (in portrait mode) and wider (in landscape mode) aspect ratio than the baseline screen configuration.
  2. notlong – resources for use only on screens that have an aspect ratio that is similar to the baseline screen configuration.

What does it mean in practice?

hvga – notlong
qvga – notlong
wqvga400 – long
wqvga432 – long
wvga800 – long
wvga854 – long

i.e. if you have aspect ration > 1.5 like 1.78 (480×854) long folders will be used by Android.

For example if you scale layout hvga (1.5) to wvga854 (1.78) – you should take into account additional 480*1.5=720; 854-730=134 pixels in the middle.

p.s. Motorola Flipout is notlong also because it is just landscape qvga.

//DL

How weight in LinearLayout works

This post is just a quick review of LinearLayout weight attribute.
Here’re a few things:

  1. If you want to divide the space equally between Views with the same weight – set 0dp as Views’ width
  2. If you set View width to wrap_content – size of the Views will depend on weight and content inside each View

hope it will help you to better understand LinearLayout weight idea.

//DL

Android 1.6: strange things happen with UI

For some reason I had the complex layout:

<LinearLayout
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
..
<FrameLayout
	android:layout_height="fill_parent"
	android:layout_width="fill_parent"
...
<ListView
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"

ListView scroll worked perfectly on 1.5 and 1.6. At some point of time layout was changed to:

<LinearLayout
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"
..
<FrameLayout
	android:layout_height="wrap_content"
	android:layout_weight="1"
	android:layout_width="fill_parent"
...
<ListView
	android:layout_width="fill_parent"
	android:layout_height="fill_parent"

and performance decreased dramatically on 1.6 (looks like x10 worse)… same layout works fine on 1.5. It took me a day to find this problem out.

be careful with layouts!

onLongClick custom selection

If you want to make custom Listview selection you may probably need custom longclick selection (to show long click in action). This may be done with transtion tag in android.
Continue reading

Layout secrets: “layer-list” and “include”

layer-list

You can simple combine several drawables into one using <layer-list> tag.

Continue reading

© 2017 Android Tales

Theme by Anders NorenUp ↑