Android編程實(shí)現(xiàn)支持拖動(dòng)改變位置的圖片中疊加文字功能示例
本文實(shí)例講述了Android編程實(shí)現(xiàn)支持拖動(dòng)改變位置的圖片中疊加文字功能。分享給大家供大家參考,具體如下:
之所以做了這么一個(gè)Demo,是因?yàn)樽罱?xiàng)目中有一個(gè)奇葩的需求:用戶(hù)拍攝照片后,分享到微信的同時(shí)添加備注,想獲取用戶(hù)在微信的彈出框輸入的內(nèi)容,保存在自己的服務(wù)器上。而事實(shí)上,這個(gè)內(nèi)容程序是無(wú)法獲取的,因此采取了一個(gè)折衷方案,將文字直接寫(xiě)在圖片上。
首先上Demo效果圖:
功能:
1.用戶(hù)自由輸入內(nèi)容,可手動(dòng)換行,并且行滿(mǎn)也會(huì)自動(dòng)換行。
2.可拖動(dòng)改變圖片中文本位置(文字不會(huì)超出圖片區(qū)域)。
3.點(diǎn)擊“生成圖片”按鈕之后,生成一張帶有文字的圖片文件。
代碼不多,直接全部貼上了:
Activity:
/** * 將文字寫(xiě)在圖片中(截圖方式),支持拖動(dòng)文字。<br/> * 說(shuō)明:很明顯,截圖方式會(huì)降低圖片的質(zhì)量。如果需要保持圖片質(zhì)量可以使用canvas的方式,將文字直接繪制在圖片之上(不過(guò),使用此方式要實(shí)現(xiàn)文字拖動(dòng)較為復(fù)雜)。 */ public class MainActivity extends AppCompatActivity { //圖片組件 private ImageView imageView; //位于圖片中的文本組件 private TextView tvInImage; //圖片和文本的父組件 private View containerView; //父組件的尺寸 private float imageWidth, imageHeight, imagePositionX, imagePositionY; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.image_with_text); imageView = (ImageView) findViewById(R.id.writeText_img); EditText editText = (EditText) findViewById(R.id.writeText_et); tvInImage = (TextView) findViewById(R.id.writeText_image_tv); containerView = findViewById(R.id.writeText_img_rl); imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this); imagePositionX = imageView.getX(); imagePositionY = imageView.getY(); imageWidth = imageView.getWidth(); imageHeight = imageView.getHeight(); //設(shè)置文本大小 tvInImage.setMaxWidth((int) imageWidth); } }); imageView.setImageBitmap(getScaledBitmap(R.mipmap.test_img)); //輸入框 editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (s.toString().equals("")) { tvInImage.setVisibility(View.INVISIBLE); } else { tvInImage.setVisibility(View.VISIBLE); tvInImage.setText(s); } } @Override public void afterTextChanged(Editable s) { } }); final GestureDetector gestureDetector = new GestureDetector(this, new SimpleGestureListenerImpl()); //移動(dòng) tvInImage.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { gestureDetector.onTouchEvent(event); return true; } }); } //確認(rèn),生成圖片 public void confirm(View view) { Bitmap bm = loadBitmapFromView(containerView); String filePath = Environment.getExternalStorageDirectory() + File.separator + "image_with_text.jpg"; try { bm.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath)); Toast.makeText(this, "圖片已保存至:SD卡根目錄/image_with_text.jpg", Toast.LENGTH_LONG).show(); } catch (FileNotFoundException e) { e.printStackTrace(); } } //以圖片形式獲取View顯示的內(nèi)容(類(lèi)似于截圖) public static Bitmap loadBitmapFromView(View view) { Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; } private int count = 0; //tvInImage的x方向和y方向移動(dòng)量 private float mDx, mDy; //移動(dòng) private class SimpleGestureListenerImpl extends GestureDetector.SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { //向右移動(dòng)時(shí),distanceX為負(fù);向左移動(dòng)時(shí),distanceX為正 //向下移動(dòng)時(shí),distanceY為負(fù);向上移動(dòng)時(shí),distanceY為正 count++; mDx -= distanceX; mDy -= distanceY; //邊界檢查 mDx = calPosition(imagePositionX - tvInImage.getX(), imagePositionX + imageWidth - (tvInImage.getX() + tvInImage.getWidth()), mDx); mDy = calPosition(imagePositionY - tvInImage.getY(), imagePositionY + imageHeight - (tvInImage.getY() + tvInImage.getHeight()), mDy); //控制刷新頻率 if (count % 5 == 0) { tvInImage.setX(tvInImage.getX() + mDx); tvInImage.setY(tvInImage.getY() + mDy); } return true; } } //計(jì)算正確的顯示位置(不能超出邊界) private float calPosition(float min, float max, float current) { if (current < min) { return min; } if (current > max) { return max; } return current; } //獲取壓縮后的bitmap private Bitmap getScaledBitmap(int resId) { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; BitmapFactory.decodeResource(getResources(), resId, opt); opt.inSampleSize = Utility.calculateInSampleSize(opt, 600, 800); opt.inJustDecodeBounds = false; return BitmapFactory.decodeResource(getResources(), resId, opt); } }
一個(gè)工具類(lèi):
public class Utility { //計(jì)算 inSampleSize 值,壓縮圖片 public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="10dp"> <RelativeLayout android:id="@+id/writeText_img_rl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal"> <ImageView android:id="@+id/writeText_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxHeight="360dp" android:adjustViewBounds="true" android:contentDescription="@null"/> <TextView android:id="@+id/writeText_image_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" android:layout_centerInParent="true" android:background="#79652a" android:clickable="true" android:padding="4dp" android:textColor="@android:color/white" android:textSize="15sp" /> </RelativeLayout> <EditText android:id="@+id/writeText_et" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:hint="添加備注" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="confirm" android:text="生成圖片" /> </LinearLayout>
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Android圖形與圖像處理技巧總結(jié)》、《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》、《Android調(diào)試技巧與常見(jiàn)問(wèn)題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
HorizontalScrollView水平滾動(dòng)控件使用方法詳解
這篇文章主要為大家詳細(xì)介紹了HorizontalScrollView水平滾動(dòng)控件的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08UI 開(kāi)源組件Flutter圖表范圍選擇器使用詳解
這篇文章主要為大家介紹了UI 開(kāi)源組件Flutter圖表范圍選擇器使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08ReactiveCocoa代碼實(shí)踐之-RAC網(wǎng)絡(luò)請(qǐng)求重構(gòu)
這篇文章主要介紹了ReactiveCocoa代碼實(shí)踐之-RAC網(wǎng)絡(luò)請(qǐng)求重構(gòu) 的相關(guān)資料,需要的朋友可以參考下2016-04-04Android基于開(kāi)源項(xiàng)目xutils3實(shí)現(xiàn)下載
這篇文章主要介紹了Android基于開(kāi)源項(xiàng)目xutils3實(shí)現(xiàn)下載,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11Android線(xiàn)程管理之ActivityThread
線(xiàn)程通信、ActivityThread及Thread類(lèi)是理解Android線(xiàn)程管理的關(guān)鍵。通過(guò)本文給大家介紹Android線(xiàn)程管理之ActivityThread 的相關(guān)知識(shí),對(duì)android線(xiàn)程管理相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-01-01Android應(yīng)用開(kāi)發(fā)中Fragment的靜態(tài)加載與動(dòng)態(tài)加載實(shí)例
這篇文章主要介紹了Android應(yīng)用開(kāi)發(fā)中Fragment的靜態(tài)加載與動(dòng)態(tài)加載實(shí)例,例子中包括動(dòng)態(tài)的添加更新以及刪除Fragment等操作,很有借鑒意義,需要的朋友可以參考下2016-02-02Android如何動(dòng)態(tài)改變App桌面圖標(biāo)
這篇文章主要介紹了 Android動(dòng)態(tài)改變App桌面圖標(biāo)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01Android ExpandableRecyclerView使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android ExpandableRecyclerView的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08