Tuesday, January 31, 2017

Spannable TextView with Image clickable


1.activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:gravity="center"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

2.MainActivity.java

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Selection;
import android.text.Spannable;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView textView = (TextView) findViewById(R.id.textView);
        String text = "Image $ span";
        int $index = text.indexOf("$");

        Spannable span = Spannable.Factory.getInstance().newSpannable(text);
        span.setSpan(new ImageSpan(getBaseContext(), android.R.drawable.star_on),
                $index, $index + 1,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        //for on image click
        span.setSpan(new ClickableSpan() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "Image is clicked", Toast.LENGTH_SHORT).show();
            }
        }, $index, $index + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(span);

        //for image clickable
        textView.setMovementMethod(new LinkMovementMethod() {
            @Override
            public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
                Selection.removeSelection(buffer);
                widget.setHighlightColor(Color.argb(0,0,0,0));
                return super.onTouchEvent(widget, buffer, event);
            }
        });
    }
}

Using glide to show GIF in ImageView

As you know glide is an image loading and caching library for Android focused on smooth scrolling. Glide is a fast and efficient open source media management and image loading framework for Android that wraps media decoding, memory and disk caching, and resource pooling into a simple and easy to use interface. You can use Glide to load GIF image from drawable or URL.

1.build.gradle

Add the glide dependency to your build.gradle.
dependencies {
    // glide
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

2.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:gravity="center"
    android:orientation="vertical" >
    <ImageView
        android:id="@+id/image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

3.MainActivity.java

Load gif image from drawable :
import android.app.Activity;
import android.os.Bundle;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.GlideDrawableImageViewTarget;

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView imageView = (ImageView) findViewById(R.id.image);
        Glide.with(this).load(R.drawable.loader).asGif().into(imageView);

        /*Or use below code*/
        /*GlideDrawableImageViewTarget imageViewTarget = new GlideDrawableImageViewTarget(imageView);
        Glide.with(this).load(R.drawable.loader).into(imageViewTarget);*/
    }
}

Load gif image from Internet :
Glide.with(this)
                .load("https://i.stack.imgur.com/h6viz.gif")
                .crossFade()
                .into(imageView);
**Note**
At the first run, it will take some time to load the image.

Monday, January 30, 2017

Limit EditText's length in Byte

When writing text using EditText on Android, you may need to limit the length in bytes. SMS, and MMS transmission will be typical examples. If we send messages only in English, there will be no problem, but in Hangul, it is expressed as 2 ~ 3 Bytes. The device I am currently dealing with is 3Byte, so I do not know why, but for stability. However, if you read the Byte using CharSet, you can express it in 2bytes.

1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:orientation="vertical" >
    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#fff"
        android:inputType="text"/>
</LinearLayout>

2.MainActivity.java

import android.app.Activity;
import android.os.Bundle;
import android.text.InputFilter;
import android.text.Spanned;
import android.widget.EditText;

import java.io.UnsupportedEncodingException;

public class MainActivity extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.editText);
        InputFilter[] byteFilter = new InputFilter[]{new ByteLengthFilter(10, "KSC5601")};
        editText.setFilters(byteFilter);
    }

    class ByteLengthFilter implements InputFilter {
        private String mCharset;
        protected int mMaxByte;
        public ByteLengthFilter(int maxbyte, String charset) {
            this.mMaxByte = maxbyte;
            this.mCharset = charset;
        }

        public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
            String expected = new String();
            expected += dest.subSequence(0, dstart);
            expected += source.subSequence(start, end);
            expected += dest.subSequence(dend, dest.length());
            int keep = calculateMaxLength(expected) - (dest.length() - (dend - dstart));
            if(keep < 0) {
                keep = 0;
            }
            int Rekeep = plusMaxLength(dest.toString(), source.toString(), start);

            if (keep <= 0 && Rekeep <= 0) {
                return "";

            }
            else if (keep >= end - start) {
                return null;
            }
            else {
                if( dest.length() == 0 && Rekeep <= 0 ) {
                    return source.subSequence(start, start + keep);
                }
                else if(Rekeep <= 0) {
                    return source.subSequence(start, start + (source.length()-1));
                }
                else {
                    return source.subSequence(start, start + Rekeep);
                }
            }
        }
        protected int plusMaxLength( String expected, String source, int start ) {
            int keep = source.length();
            int maxByte = mMaxByte - getByteLength(expected.toString());

            while (getByteLength(source.subSequence(start, start + keep).toString()) > maxByte) {
                keep--;
            };
            return keep;
        }

        protected int calculateMaxLength(String expected) {
            int expectedByte = getByteLength(expected);
            if (expectedByte == 0) {
                return 0;
            }
            return mMaxByte - (getByteLength(expected) - expected.length());
        }
        private int getByteLength(String str) {
            try {
                return str.getBytes(mCharset).length;
            } catch (UnsupportedEncodingException e) {

            }
            return 0;
        }
    }
}

Get height of the view

Method getHeight() will always return 0 cause you are trying to get the size before the view is drawn, another possible solution could be to do a Post with a runnable on the View.

1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:orientation="vertical" >
        <ImageView
            android:id="@+id/image"
            android:layout_gravity="center"
            android:layout_height="300dp"
            android:layout_width="300dp"
            android:src="@mipmap/ic_launcher"/>
</LinearLayout>

2.MainActivity.java

    final ImageView imageView = (ImageView) findViewById(R.id.image);
        Log.d("TEST", "" + imageView.getHeight());
        //Will return height = 0;

        imageView.post(new Runnable(){
            public void run(){
                Log.d("TEST", "" + imageView.getHeight());
                //Will return specific height
            }
        });

Saturday, January 28, 2017

Filter ListView when enter text in EditText

This is how to filter a ListView based on user input.

1.activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    <EditText
        android:id="@+id/search_box"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="Search"
        android:inputType="text"
        android:maxLines="1"/>
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1"/>
</LinearLayout>

2.MainActivity.java

public class MainActivity extends ListActivity {
    private EditText filterText = null;
    ArrayAdapter<String> adapter = null;
    String[] list = new String[]{"a", "b", "c", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"};
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        filterText = (EditText) findViewById(R.id.search_box);
        filterText.addTextChangedListener(filterTextWatcher);
        adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
                list);
        setListAdapter(adapter);
    }

    private TextWatcher filterTextWatcher = new TextWatcher() {
        public void afterTextChanged(Editable s) {}

        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        public void onTextChanged(CharSequence s, int start, int before, int count) {
            adapter.getFilter().filter(s.toString());
        }
    };

    protected void onDestroy() {
        super.onDestroy();
        filterText.removeTextChangedListener(filterTextWatcher);
    }
}

Format EditText number with comma

This is how to format number with comma of an EditText when we enter the number.

1.activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:orientation="vertical" >
    <EditText
        android:id="@+id/et_number"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#fff"
        android:imeOptions="actionDone"
        android:inputType="number|text"
        android:maxLines="1"
        android:maxLength="17"
        android:textColor="#000"
        android:textSize="17sp"
        android:textStyle="bold" />
</LinearLayout>

2.MainActivity.java

public class MainActivity extends Activity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.et_number);
        editText.addTextChangedListener(new TextWatcher() {
            boolean isEdiging;

            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            public void afterTextChanged(Editable s) {
                if (isEdiging) return;
                isEdiging = true;
                String str = s.toString().replaceAll("[^\\d]", "");
                double s1 = 0;
                try {
                    s1 = Double.parseDouble(str);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                NumberFormat nf2 = NumberFormat.getInstance(Locale.ENGLISH);
                ((DecimalFormat) nf2).applyPattern("###,###.###");
                s.replace(0, s.length(), nf2.format(s1));

                if (s.toString().equals("0")) {
                    editText.setText("");
                }
                isEdiging = false;
            }
        });
    }
}

Custom EditText Cursor

Customize the cursor of an EditText is the easy way, by using xml in drawable.


Create an xml in drawable folder :

1.green_cursor.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >
    <size
        android:width="2dip" />
    <solid
        android:color="#7119bf37" />
    <padding
        android:top="0dp"
        android:bottom="0dp" />
</shape>

2.In layout_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e6e6e6"
    android:orientation="vertical" >
    <EditText
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#fff"
        android:inputType="number"
        android:maxLength="16"
        android:textCursorDrawable="@drawable/green_cursor"
        android:minWidth="40dp"
        android:textColor="#000000"
        android:textSize="17sp"
        android:textStyle="bold" />
</LinearLayout>

Set Dialog position to bottom and remove default margins

Tags
Default position of the dialog is at the middle of the screen. This example show you, how to change the position of the dialog to bottom.

1.layout_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:gravity="bottom"
    android:background="@color/black_overlay">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="#fff">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="15dp"
            android:layout_marginLeft="10dp"
            android:text="MENU"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginTop="5dp"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@android:drawable/ic_menu_edit" />
            <TextView
                android:id="@+id/tv_edit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Edit"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="10dp"
            android:gravity="center_vertical"
            android:orientation="horizontal">
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="@android:drawable/ic_delete" />
            <TextView
                android:id="@+id/tv_delete"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Delete"/>
        </LinearLayout>
    </LinearLayout>
</LinearLayout>



2.style.xml

Add style to style.xml
<style name="DialogTheme" parent="Theme.AppCompat.Light.Dialog">
    <!-- Customize your theme here. -->   
    <item name="android:windowBackground">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">false</item>
</style>

3.DialogMenu.java

public class DialogMenu implements View.OnClickListener{
    public DialogMenu(Context context) {
        Dialog dialog = new Dialog(context, R.style.DialogTheme);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setContentView(R.layout.layout_menu);
        dialog.getWindow().setGravity(Gravity.BOTTOM);
        dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
        dialog.show();

        TextView tv_edit = (TextView) dialog.findViewById(R.id.tv_edit);
        TextView tv_delete = (TextView) dialog.findViewById(R.id.tv_delete);
        tv_edit.setOnClickListener(this);
        tv_delete.setOnClickListener(this);

    }

    public void onClick(View view) {
        switch (view.getId()){
            case R.id.tv_edit :
                Log.d("Test ", " 1 ");
                break;
            case R.id.tv_delete :
                Log.d("Test ", " 2 ");
                break;
        }
    }
}

4.Usage

new DialogMenu(MainActivity.this);