时间:2019.03.25~2019.03.29
需求
要求根据文本内容对背景图片自动做裁剪?
什么意思呢?
就是给你一张图,当文本显示两行的时候,全部显示。
如果只显示一行,那么就显示上半部分。
为了便于理解,这边自己用 sketch 做了一张背景图。
这里要求当你文本显示一行,只显示上面第一个色块,当文本为两行时,显示两个色块。
分析
既然需求出来了,那么我们就开始进行分析。
这里最重要的其实是拆分思维。这个需求其实可以拆为两个小需求。
如果你能够解决这两个小需求,那么这个需求也就迎刃而解了。
图片裁剪
如何进行图片裁剪呢?
其实很简单,只要在 drawable 下面创建一个 xml 文件即可。
模板代码如下:
<?xml version="1.0" encoding="utf-8"?><clip xmlns:android="http://schemas.android.com/apk/res/android" android:clipOrientation="vertical" android:drawable="@mipmap/img_bg" android:gravity="top"/>
参数解析:
clipOrientation 你可以认为是裁剪的对齐方向,这里设置为 vertical,说明我们想保留的是竖直方向。而我们上面的需求确实是这样的,两个色块,在竖直方向为上和下。
drawable 就是要操作的图片了。
gravity 你可以认为是裁剪要保留具体哪部分。比如这里竖直方向有上和下,那么你是要保留上面还是下面呢?
说起来有点难以理解,我们通过下面 4 种情况的图片再结合上面说明你就理解了。
看这个图两个字段两两组合的情况相信你应该能够理解了。
准备好了 xml,还没有完哦~
我们这边在界面 xml 设置一个 ImageView 来演示,ImageView 布局如下:
<ImageView android:id="@+id/clip_bg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/clip_bg" />
这里我们指定了 src 就是我们刚刚在 drawable 下面创建的 clip_bg.xml。
这个时候如果你激动的直接运行,会发现啥都没有?
其实也很好理解,因为你要裁剪图片,那么你是要裁一半还是要裁 25%,你至少要告诉我,不然我怎么裁,所以接下来我们要指定裁的比例。
在 MainActivity.java 里面,我们找到对应 ImageView 并设置如下:
ImageView imageView = findViewById(R.id.clip_bg);ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();clipDrawable.setLevel(50 * 100);
可以看到也很简单,不过有个比较好奇的,就是 setLevel 里面的数值,我们点进去源码,可以看到这个参数的解释:
@param level The new level, from 0 (minimum) to 10000 (maximum).
可以看到这个值是 0~10000,因此我们这里设置 5000,其实就是要裁剪一半的意思了。为了方便表示裁剪比例,所以用 50 * 100,这里的 50 就是裁剪 50% 啦。
这个时候你运行就没问题啦~
判断文本显示行数
这个方法多种多样,我们简单采取下面方法:
tv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { //tv.getLineCount() tv.getViewTreeObserver().removeOnPreDrawListener(this); return false; }});
解决问题
既然上面两个问题都可以得到解决,那么问题也就可以解决了。
我们布局如下:
<?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" >
<LinearLayout android:id="@+id/linear" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@drawable/clip_bg" >
<TextView android:id="@+id/tv" android:layout_width="20dp" android:layout_height="wrap_content" android:maxLines="2" android:ellipsize="end" />
</LinearLayout>
</LinearLayout>
主界面代码如下:
package com.nesger.androidsample;
import android.graphics.drawable.ClipDrawable;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.ViewTreeObserver;import android.widget.LinearLayout;import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final TextView tv = findViewById(R.id.tv); LinearLayout linearLayout = findViewById(R.id.linear); final ClipDrawable clipDrawable = (ClipDrawable) linearLayout.getBackground(); tv.setText("1"); changeBg(tv, clipDrawable); tv.postDelayed(new Runnable() { @Override public void run() { tv.setText(">1 is must,so just test"); changeBg(tv, clipDrawable); } }, 5000); }
private void changeBg(final TextView tv, final ClipDrawable clipDrawable) { tv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { //tv.getLineCount() tv.getViewTreeObserver().removeOnPreDrawListener(this); if (tv.getLineCount() == 1) { clipDrawable.setLevel(50 * 100); } else { clipDrawable.setLevel(100 * 100); } return false; } }); }}
这里只是简单的演示下效果而已。
源码点击阅读原文或者拷贝下面链接浏览器打开:?
https://github.com/nesger/AndroidSample
温馨提示
细心的小伙伴会发现我们在获取 ClipDrawable 的时候,对于 ImageView,使用的是
ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();
而对于 LinearLayout 使用的是
ClipDrawable clipDrawable = (ClipDrawable) linearLayout.getBackground();
因此在使用的时候,要测试一下,避免出现调用 API 错误导致空指针问题。
总结
拆分思维很重要。
一个需求,如果可以拆分成小的需求,就进行需求拆分。
当不能再拆分的时候,解决起来会比直接解决大需求要容易和快的多。
当所有小需求都解决了,大需求自然迎刃而解。