├── sample ├── lint.xml ├── libs │ └── android-support-v4.jar ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── values-sw600dp │ │ └── dimens.xml │ ├── values │ │ ├── dimens.xml │ │ ├── color.xml │ │ ├── styles.xml │ │ └── strings.xml │ ├── menu │ │ └── main.xml │ ├── values-sw720dp-land │ │ └── dimens.xml │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ └── layout │ │ └── activity_main.xml ├── project.properties ├── proguard-project.txt ├── AndroidManifest.xml └── src │ └── ir │ └── mohsennavabi │ └── justifiedtextviewtest │ └── MainActivity.java ├── raw └── JustifiedTextView.png ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── values │ ├── strings.xml │ └── styles.xml ├── values-v11 │ └── styles.xml └── values-v14 │ └── styles.xml ├── AndroidManifest.xml ├── .gitignore ├── project.properties ├── proguard-project.txt ├── README.md └── src └── ir └── noghteh ├── XmlToClassAttribHandler.java └── JustifiedTextView.java /sample/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /raw/JustifiedTextView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/raw/JustifiedTextView.png -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | JustifiedTextViewLibrary 4 | 5 | -------------------------------------------------------------------------------- /sample/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/sample/libs/android-support-v4.jar -------------------------------------------------------------------------------- /sample/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/sample/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/sample/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/sample/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/navabi/JustifiedTextView/HEAD/sample/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 20sp 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /sample/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /sample/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/res/values/color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #FF5000 5 | #F84545 6 | #30E35A 7 | #309BE3 8 | #E2E2E2 9 | #F1F1F1 10 | #D2D2D2 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /sample/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | /.settings/org.eclipse.jdt.core.prefs 15 | /sample/.settings/org.eclipse.jdt.core.prefs 16 | /sample/bin/ 17 | /sample/gen/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | /sample/local.properties 22 | 23 | # Eclipse project files 24 | .classpath 25 | .project 26 | /sample/.classpath 27 | /sample/.project 28 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-18 15 | android.library=true 16 | -------------------------------------------------------------------------------- /sample/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-19 15 | android.library.reference.1=.. 16 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /sample/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /sample/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /sample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JustifiedTextView for Android 2 | 3 | This project provides a view for android apps that implements justified text view. 4 | 5 | ![Screenshot](https://raw.github.com/navabi/JustifiedTextView/master/raw/JustifiedTextView.png) 6 | 7 | Android 2.0+ support 8 | 9 | ## Quick Setup 10 | 11 | #### 1. Include library 12 | 13 | **Manual:** 14 | * Downlaod the JustifiedTextView Library 15 | * Add it to your eclipse workspace 16 | * there is a sample project with the library that you can import as well 17 | * Go to your project properties and add JustifiedTextView as library 18 | 19 | #### 2. Application class 20 | ``` java 21 | public class MainActivity extends Activity { 22 | 23 | private JustifiedTextView mJTv; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_main); 29 | 30 | mJTv=(JustifiedTextView) findViewById(R.id.activity_main_jtv_text); 31 | mJTv.setText(getResources().getString(R.string.test)); 32 | mJTv.setTextSize(TypedValue.COMPLEX_UNIT_SP,20); 33 | mJTv.setLineSpacing(15); 34 | mJTv.setBackgroundColor(Color.RED); 35 | mJTv.setAlignment(Align.LEFT); 36 | mJTv.setTypeFace(Typeface.createFromAsset(getAssets(), "fonts/naskh_bold.ttf")); 37 | 38 | } 39 | } 40 | ``` 41 | 42 | ## 3. Xml 43 | ``` xml 44 | 49 | 50 | 61 | 62 | 63 | 64 | ``` 65 | 66 | 67 | ## 4.License 68 | please inform us if you use this library ( navabi70-at-gmail) 69 | 70 | Copyright 2013-2014 Mohsen Navabi 71 | 72 | -------------------------------------------------------------------------------- /sample/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | JustifiedTextViewTest 5 | Settings 6 | در اوت ۲۰۰۵، گوگل شرکت اندروید واقع در پالو آلتو، کالیفرنیا را خرید. شرکت کوچک اندروید که توسط اندی رابین، ریچ ماینرز، نیک سیرز و کریس وایت پایه‌گذاری شده بود، در زمینه تولید نرم‌افزار و برنامه‌های کاربردی برای تلفن‌های همراه فعالیت می‌کرد. اندی رابین مدیر عامل اجرایی این شرکت پس از پیوستن اندروید به گوگل به سمت قائم‌مقام مدیریت مهندسی این شرکت و مسئول پروژه اندروید در گوگل منصوب شد. تیم اندروید به رهبری رابین فعالیت خود را برای تولید سکوی تلفن همراه مبتنی بر هسته لینوکس آغاز کردند و نتیجه اولیه این پروژه در نشست خبری شرکت گوگل در ۵ نوامبر سال ۲۰۰۷، مطرح کردن اتحادیه گوشی باز بود. ۳۴ شرکت فعال در زمینه تولید نرم‌افزار، تولید تلفن‌های همراه، اپراتور تلفن همراه و تولیدکننده نیمه رساناها و پردازنده‌های تلفن همراه اعضای بنیان‌گذار این اتحادیه بودند. در میان نام‌های مشهور در بین اعضای مؤسس، شرکت‌هایی چون سامسونگ، ال‌جی الکترونیکس، موتورولا، اچ‌تی‌سی، تی-موبایل، ان‌تی‌تی دوکومو، اینتل، انویدیا، تگزاس اینسترومنتس، کوالکام، برودکام، تلفونیکا، اسپرینت، ای‌بی و البته گوگل به چشم می‌خوردند. اریک اشمیت مدیر ارشد اجرایی گوگل در این مراسم گفت: «اعلام امروز بسیار جاه‌طلبانه‌تر از معرفی تنها یک تلفن گوگلی است که در چند هفته اخیر توسط رسانه‌ها پیش‌بینی شده بود. از دیدگاه ما سکویی که ما ارائه کرده‌ایم، هزاران تلفن گوناگون را به بازار روانه خواهد کرد.» نخستین گوشی مبتنی بر اندروید توسط شرکت اچ‌تی‌سی با همکاری تی-موبایل تولید شد. این گوشی که به فاصله کمتر از یک سال از تشکیل اتحادیه گوشی باز یعنی در ۲۲ اکتبر ۲۰۰۸ تولید شد، در بازارهای مختلف به نام‌های اچ‌تی‌سی دریم، تی-موبایل جی۱ و ارا جی۱ به بازار عرضه گردید. 7 | Google acquired Android Inc. on August 17, 2005; key employees of Android Inc., including Rubin, Miner, and White, stayed at the company after the acquisition.Not much was known about Android Inc. at the time, but many assumed that Google was planning to enter the mobile phone market with this move.At Google, the team led by Rubin developed a mobile device platform powered by the Linux kernel. Google marketed the platform to handset makers and carriers on the promise of providing a flexible, upgradable system. Google had lined up a series of hardware component and software partners and signaled to carriers that it was open to various degrees of cooperation on their part. 8 | Speculation about Google\'s intention to enter the mobile communications market continued to build through December 2006.An earlier prototype codenamed "Sooner" had a closer resemblance to a BlackBerry phone, with no touchscreen, and a physical, QWERTY keyboard, but was later re-engineered to support a touchscreen, to compete with other announced devices such as the 2006 LG Prada and 2007 Apple iPhone.In September 2007, InformationWeek covered an Evalueserve study reporting that Google had filed several patent applications in the area of mobile telephony 9 | 10 | -------------------------------------------------------------------------------- /sample/src/ir/mohsennavabi/justifiedtextviewtest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package ir.mohsennavabi.justifiedtextviewtest; 2 | 3 | import ir.noghteh.JustifiedTextView; 4 | import android.os.Bundle; 5 | import android.app.Activity; 6 | import android.graphics.Paint.Align; 7 | import android.util.Log; 8 | import android.util.TypedValue; 9 | import android.view.Menu; 10 | import android.view.View; 11 | import android.view.View.OnClickListener; 12 | import android.widget.LinearLayout; 13 | import android.widget.SeekBar; 14 | import android.widget.SeekBar.OnSeekBarChangeListener; 15 | import android.widget.TextView; 16 | 17 | public class MainActivity extends Activity implements OnClickListener, 18 | OnSeekBarChangeListener { 19 | 20 | private JustifiedTextView mJTv; 21 | private TextView mTv; 22 | private SeekBar mSbSize; 23 | private LinearLayout mLlGreen, mLlRed; 24 | private TextView mTvEng, mTvFa; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_main); 30 | initViews(); 31 | } 32 | 33 | private void initViews() { 34 | mJTv = (JustifiedTextView) findViewById(R.id.activity_main_jtv); 35 | mTv = (TextView) findViewById(R.id.activity_main_tv); 36 | mLlGreen = (LinearLayout) findViewById(R.id.activity_main_ll_green); 37 | mLlRed = (LinearLayout) findViewById(R.id.activity_main_ll_red); 38 | mTvEng = (TextView) findViewById(R.id.activity_main_tv_eng); 39 | mTvFa = (TextView) findViewById(R.id.activity_main_tv_fa); 40 | 41 | mSbSize = (SeekBar) findViewById(R.id.activity_main_sb_size); 42 | mSbSize.setMax(20); 43 | mSbSize.setProgress(10); 44 | 45 | mSbSize.setOnSeekBarChangeListener(this); 46 | 47 | mLlGreen.setOnClickListener(this); 48 | mLlRed.setOnClickListener(this); 49 | mTvEng.setOnClickListener(this); 50 | mTvFa.setOnClickListener(this); 51 | } 52 | 53 | @Override 54 | public void onClick(View arg0) { 55 | switch (arg0.getId()) { 56 | case R.id.activity_main_ll_red: 57 | mJTv.setTextColor(getResources().getColor(R.color.red)); 58 | mTv.setTextColor(getResources().getColor(R.color.red)); 59 | break; 60 | case R.id.activity_main_ll_green: 61 | mJTv.setTextColor(getResources().getColor(R.color.green)); 62 | mTv.setTextColor(getResources().getColor(R.color.green)); 63 | break; 64 | case R.id.activity_main_tv_eng: 65 | mJTv.setAlignment(Align.LEFT); 66 | mJTv.setText(R.string.text_eng); 67 | mTv.setText(R.string.text_eng); 68 | break; 69 | case R.id.activity_main_tv_fa: 70 | mJTv.setAlignment(Align.RIGHT); 71 | mJTv.setText(R.string.text_fa); 72 | mTv.setText(R.string.text_fa); 73 | break; 74 | default: 75 | break; 76 | } 77 | } 78 | 79 | @Override 80 | public void onProgressChanged(SeekBar arg0, int pos, boolean arg2) { 81 | 82 | int size = 10; 83 | mTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, pos + size); 84 | mJTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, pos + size); 85 | mJTv.setLineSpacing(pos - size); 86 | mTv.setLineSpacing(pos - size, 1); 87 | } 88 | 89 | @Override 90 | public void onStartTrackingTouch(SeekBar arg0) { 91 | 92 | } 93 | 94 | @Override 95 | public void onStopTrackingTouch(SeekBar arg0) { 96 | 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/ir/noghteh/XmlToClassAttribHandler.java: -------------------------------------------------------------------------------- 1 | package ir.noghteh; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.graphics.Color; 6 | import android.util.AttributeSet; 7 | import android.util.TypedValue; 8 | 9 | public class XmlToClassAttribHandler { 10 | private Resources mRes; 11 | private Context mContext; 12 | private AttributeSet mAttributeSet; 13 | 14 | private String namespace="http://noghteh.ir"; 15 | private final String KEY_TEXT="text"; 16 | private final String KEY_TEXT_SIZE="textSize"; 17 | private final String KEY_TEXT_COLOR="textColor"; 18 | 19 | public XmlToClassAttribHandler(Context context,AttributeSet attributeSet){ 20 | mContext=context; 21 | mRes=mContext.getResources(); 22 | mAttributeSet=attributeSet; 23 | 24 | 25 | } 26 | 27 | public String getTextValue(){ 28 | 29 | String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT); 30 | 31 | if (value==null) 32 | return ""; 33 | 34 | if (value.length()>1 && 35 | value.charAt(0)=='@' && 36 | value.contains("@string/")){ 37 | int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null); 38 | value=mRes.getString(resId); 39 | } 40 | 41 | return value; 42 | 43 | } 44 | 45 | public int getColorValue(){ 46 | 47 | String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_COLOR); 48 | 49 | int color=Color.BLACK; 50 | 51 | if (value==null) 52 | return color; 53 | 54 | if (value.length()>1 && 55 | value.charAt(0)=='@' && 56 | value.contains("@color/")){ 57 | int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null); 58 | color=mRes.getColor(resId); 59 | 60 | return color; 61 | } 62 | 63 | 64 | try{ 65 | color=Color.parseColor(value); 66 | } 67 | catch(Exception e){ 68 | return Color.BLACK; 69 | } 70 | 71 | 72 | return color; 73 | } 74 | 75 | 76 | public int getTextSize() { 77 | int textSize=12; 78 | 79 | String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_SIZE ); 80 | 81 | if (value==null) 82 | return textSize; 83 | 84 | if (value.length()>1 && 85 | value.charAt(0)=='@' && 86 | value.contains("@dimen/")){ 87 | int resId=mRes.getIdentifier(mContext.getPackageName()+":"+value.substring(1), null,null); 88 | textSize=mRes.getDimensionPixelSize(resId); 89 | 90 | return textSize; 91 | } 92 | 93 | try{ 94 | textSize=Integer.parseInt(value.substring(0, value.length()-2)); 95 | } 96 | catch(Exception e){ 97 | return 12; 98 | } 99 | 100 | return textSize; 101 | } 102 | 103 | 104 | public int gettextSizeUnit() { 105 | 106 | String value=mAttributeSet.getAttributeValue(namespace, KEY_TEXT_SIZE ); 107 | 108 | if (value==null) 109 | return TypedValue.COMPLEX_UNIT_SP; 110 | 111 | try{ 112 | String type=value.substring(value.length()-2, value.length()); 113 | 114 | if (type.equals("dp")) 115 | return TypedValue.COMPLEX_UNIT_DIP; 116 | else if (type.equals("sp")) 117 | return TypedValue.COMPLEX_UNIT_SP; 118 | else if (type.equals("pt")) 119 | return TypedValue.COMPLEX_UNIT_PT; 120 | else if (type.equals("mm")) 121 | return TypedValue.COMPLEX_UNIT_MM; 122 | else if (type.equals("in")) 123 | return TypedValue.COMPLEX_UNIT_IN; 124 | else if (type.equals("px")) 125 | return TypedValue.COMPLEX_UNIT_PX; 126 | } 127 | catch(Exception e){ 128 | return -1; 129 | } 130 | 131 | return -1; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /sample/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 19 | 20 | 30 | 31 | 32 | 33 | 39 | 40 | 45 | 46 | 55 | 56 | 57 | 63 | 64 | 69 | 70 | 71 | 78 | 79 | 80 | 87 | 88 | 89 | 98 | 99 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/ir/noghteh/JustifiedTextView.java: -------------------------------------------------------------------------------- 1 | package ir.noghteh; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import android.content.Context; 7 | import android.graphics.Canvas; 8 | import android.graphics.Paint.Align; 9 | import android.graphics.Rect; 10 | import android.graphics.Typeface; 11 | import android.text.TextPaint; 12 | import android.util.AttributeSet; 13 | import android.util.Log; 14 | import android.util.TypedValue; 15 | import android.view.View; 16 | import android.view.ViewTreeObserver; 17 | import android.view.ViewTreeObserver.OnGlobalLayoutListener; 18 | 19 | /** 20 | * @author Mohsen Navabi 21 | * @version 1.0 22 | * @see http://www.mohsennavabi.ir 23 | * @see http://www.noghteh.ir 24 | */ 25 | public class JustifiedTextView extends View { 26 | 27 | private Context mContext; 28 | 29 | private XmlToClassAttribHandler mXmlParser; 30 | 31 | private TextPaint textPaint; 32 | 33 | private int lineSpace=0; 34 | 35 | private int lineHeight; 36 | 37 | private int textAreaWidth; 38 | 39 | private int measuredViewHeight,measuredViewWidth; 40 | 41 | private String text; 42 | 43 | private List lineList=new ArrayList(); 44 | 45 | 46 | /** 47 | * when we want to draw text after view created to avoid loop in drawing we use this boolean 48 | */ 49 | boolean hasTextBeenDrown=false; 50 | 51 | public JustifiedTextView(Context context, AttributeSet attrs, int defStyle) { 52 | super(context, attrs, defStyle); 53 | constructor(context,attrs); 54 | } 55 | public JustifiedTextView(Context context, AttributeSet attrs) { 56 | super(context, attrs); 57 | constructor(context,attrs); 58 | } 59 | public JustifiedTextView(Context context) { 60 | super(context); 61 | constructor(context,null); 62 | 63 | } 64 | 65 | private void constructor(Context context, AttributeSet attrs) { 66 | 67 | mContext=context; 68 | mXmlParser=new XmlToClassAttribHandler(mContext,attrs); 69 | initTextPaint(); 70 | 71 | if (attrs!=null){ 72 | String text; 73 | int textColor; 74 | int textSize; 75 | int textSizeUnit; 76 | 77 | text=mXmlParser.getTextValue(); 78 | textColor=mXmlParser.getColorValue(); 79 | textSize=mXmlParser.getTextSize(); 80 | textSizeUnit=mXmlParser.gettextSizeUnit(); 81 | 82 | 83 | setText(text); 84 | setTextColor(textColor); 85 | if (textSizeUnit==-1) 86 | setTextSize(textSize); 87 | else 88 | setTextSize(textSizeUnit, textSize); 89 | 90 | // setText(XmlToClassAttribHandler.GetAttributeStringValue(mContext, attrs, namespace, key, "")); 91 | 92 | } 93 | 94 | ViewTreeObserver observer=getViewTreeObserver(); 95 | 96 | 97 | observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { 98 | 99 | @Override 100 | public void onGlobalLayout() { 101 | 102 | if (hasTextBeenDrown) 103 | return; 104 | hasTextBeenDrown=true; 105 | setTextAreaWidth(getWidth()-(getPaddingLeft()+getPaddingRight())); 106 | calculate(); 107 | 108 | } 109 | 110 | 111 | }); 112 | 113 | } 114 | 115 | private void calculate() { 116 | setLineHeight(getTextPaint()); 117 | lineList.clear(); 118 | lineList=divideOriginalTextToStringLineList(getText()); 119 | setMeasuredDimentions(lineList.size(),getLineHeight(),getLineSpace()); 120 | measure(getMeasuredViewWidth(),getMeasuredViewHeight()); 121 | } 122 | 123 | private void initTextPaint(){ 124 | textPaint=new TextPaint(TextPaint.ANTI_ALIAS_FLAG); 125 | textPaint.setTextAlign(Align.RIGHT); 126 | } 127 | 128 | @Override 129 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 130 | if (getMeasuredViewWidth()>0){ 131 | requestLayout(); 132 | setMeasuredDimension(getMeasuredViewWidth(),getMeasuredViewHeight()); 133 | } 134 | else{ 135 | super.onMeasure(widthMeasureSpec, heightMeasureSpec ); 136 | } 137 | invalidate(); 138 | } 139 | 140 | 141 | private int rowIndex=0,colIndex=0; 142 | @Override 143 | protected void onDraw(Canvas canvas) { 144 | 145 | rowIndex=getPaddingTop(); 146 | if (getAlignment()==Align.RIGHT) 147 | colIndex=getPaddingLeft()+getTextAreaWidth(); 148 | else 149 | colIndex=getPaddingLeft(); 150 | 151 | for (int i=0;i divideOriginalTextToStringLineList(String originalText) { 166 | 167 | List listStringLine=new ArrayList(); 168 | 169 | String line=""; 170 | float textWidth; 171 | 172 | String[] listParageraphes = originalText.split("\n"); 173 | 174 | for(int j=0;j0){ 237 | 238 | gapIndex=lineString.indexOf(" ", gapIndex+2); 239 | if (gapIndex==-1){ 240 | gapIndex=0; 241 | gapIndex=lineString.indexOf(" ", gapIndex+1); 242 | if (gapIndex==-1) 243 | return lineString; 244 | } 245 | 246 | lineString=lineString.substring(0, gapIndex)+ " " +lineString.substring(gapIndex+1, lineString.length()); 247 | 248 | lineWidth=textPaint.measureText(lineString); 249 | } 250 | return lineString; 251 | } 252 | /*** 253 | * this method calculate height for a line of text according to defined TextPaint 254 | * @param textPaint 255 | */ 256 | private void setLineHeight(TextPaint textPaint) { 257 | 258 | Rect bounds=new Rect(); 259 | String sampleStr="این حسین کیست که عالم همه دیوانه اوست"; 260 | textPaint.getTextBounds(sampleStr, 0,sampleStr.length(), bounds); 261 | 262 | setLineHeight(bounds.height()); 263 | 264 | } 265 | 266 | /*** 267 | * this method calculate view's height according to line count and line height and view's width 268 | * @param lineListSize 269 | * @param lineHeigth 270 | * @param lineSpace 271 | */ 272 | public void setMeasuredDimentions(int lineListSize,int lineHeigth, int lineSpace){ 273 | int mHeight=lineListSize*(lineHeigth+lineSpace)+lineSpace; 274 | 275 | mHeight+=getPaddingRight()+getPaddingLeft(); 276 | 277 | setMeasuredViewHeight(mHeight); 278 | 279 | setMeasuredViewWidth(getWidth()); 280 | } 281 | 282 | 283 | private int getTextAreaWidth() { 284 | return textAreaWidth; 285 | } 286 | private void setTextAreaWidth(int textAreaWidth) { 287 | this.textAreaWidth = textAreaWidth; 288 | } 289 | 290 | private int getLineHeight() { 291 | return lineHeight; 292 | } 293 | private int getMeasuredViewHeight() { 294 | return measuredViewHeight; 295 | } 296 | private void setMeasuredViewHeight(int measuredViewHeight) { 297 | this.measuredViewHeight = measuredViewHeight; 298 | } 299 | private int getMeasuredViewWidth() { 300 | return measuredViewWidth; 301 | } 302 | private void setMeasuredViewWidth(int measuredViewWidth) { 303 | this.measuredViewWidth = measuredViewWidth; 304 | } 305 | private void setLineHeight(int lineHeight) { 306 | this.lineHeight = lineHeight; 307 | } 308 | 309 | public String getText() { 310 | return text; 311 | } 312 | 313 | /*** 314 | * Sets the string value of the JustifiedTextView. JustifiedTextView does not accept HTML-like formatting. 315 | * Related XML Attributes 316 | * -noghteh:text 317 | * @param text 318 | */ 319 | public void setText(String text) { 320 | this.text = text; 321 | calculate(); 322 | invalidate(); 323 | } 324 | 325 | public void setText(int resid) { 326 | setText(mContext.getResources().getString(resid)); 327 | } 328 | 329 | public Typeface getTypeFace() { 330 | return getTextPaint().getTypeface(); 331 | } 332 | public void setTypeFace(Typeface typeFace) { 333 | getTextPaint().setTypeface(typeFace); 334 | } 335 | 336 | public float getTextSize() { 337 | return getTextPaint().getTextSize(); 338 | } 339 | public void setTextSize(int unit,float textSize) { 340 | textSize=TypedValue.applyDimension(unit, textSize, mContext.getResources().getDisplayMetrics()); 341 | setTextSize(textSize); 342 | } 343 | 344 | private void setTextSize(float textSize) { 345 | getTextPaint().setTextSize(textSize); 346 | calculate(); 347 | invalidate(); 348 | } 349 | 350 | public TextPaint getTextPaint() { 351 | return textPaint; 352 | } 353 | public void setTextPaint(TextPaint textPaint) { 354 | this.textPaint = textPaint; 355 | } 356 | 357 | /*** 358 | * set text color 359 | * @param textColor 360 | */ 361 | public void setTextColor(int textColor) { 362 | getTextPaint().setColor(textColor); 363 | invalidate(); 364 | } 365 | /*** 366 | * define space between lines 367 | * @param lineSpace 368 | */ 369 | public void setLineSpacing(int lineSpace) { 370 | this.lineSpace = lineSpace; 371 | invalidate(); 372 | } 373 | 374 | /*** 375 | * 376 | * @return text color 377 | */ 378 | public int getTextColor() { 379 | return getTextPaint().getColor(); 380 | } 381 | 382 | 383 | 384 | /*** 385 | * space between lines - default is 0 386 | * @return 387 | */ 388 | public int getLineSpace() { 389 | return lineSpace; 390 | } 391 | 392 | 393 | /*** 394 | * get text alignment 395 | * @return 396 | */ 397 | public Align getAlignment() { 398 | return getTextPaint().getTextAlign(); 399 | } 400 | /*** 401 | * Align text according to your language 402 | * @param align 403 | */ 404 | public void setAlignment(Align align) { 405 | getTextPaint().setTextAlign(align); 406 | invalidate(); 407 | } 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | } 417 | --------------------------------------------------------------------------------