Android USB转串口通信开发基本流程

好久没有写文章了,年前公司新开了一个项目,是和usb转串口通信相关的,需求是用安卓平板通过usb转接后与好几个外设进行通信,一直忙到最近,才慢慢闲下来,趁着这个周末不忙,记录下usb转串口通信开发的基本流程。 我们开发使用的是usb主机模式,即:安卓平板作为主机,usb外设作为从机进行数据通信。整个开发流程可以总结为以下几点: 1.发现设备 usbList = usbManager.getDeviceList();1 2 1 2 " data-snippet-id="ext.1d1481e9c3517ce217b699b6673dd389" data-snippet-saved="false" data-codota-status="done">`<span class="typ">UsbManager</span><span class="pln"> usbManager </span><span class="pun">=</span> <span class="pun">(</span><span class="typ">UsbManager</span><span class="pun">)</span><span class="pln"> context</span><span class="pun">.</span><span class="pln">getSystemService</span><span class="pun">(</span><span class="typ">Context</span><span class="pun">.</span><span class="pln">USB_SERVICE</span><span class="pun">);</span> <span class="typ">Map</span><span class="pun"><</span><span class="typ">String</span><span class="pun">,</span> <span class="typ">UsbDevice</span><span class="pun">></span><span class="pln"> usbList </span><span class="pun">=</span><span class="pln"> usbManager</span><span class="pun">.</span><span class="pln">getDeviceList</span><span class="pun">();</span>` 通过UsbManager这个系统提供的类,我们可以枚举出当前连接的所有usb设备,我们主要需要的是UsbDevice对象,关于UsbDevice这个类,官方是这样注释的: `<span class="typ">This</span> <span class="kwd">class</span><span class="pln"> represents a USB device attached to the android device </span><span class="kwd">with</span><span class="pln"> the android device acting </span><span class="kwd">as</span><span class="pln"> the USB host</span><span class="pun">.</span>` 是的,这个类就代表了android所连接的usb设备。 ...

2017年10月19日 · 3 分钟 · 天边的星星

Android布局中的空格和占一个汉字宽度的空格的实现

在Android布局中进行使用到空格,以便实现文字的对齐。那么在android中如何表示一个空格呢? 注:下面的#160,#8201等等皆需要加上&方可实现效果 空格:#160; 窄空格:#8201; 一个汉字宽度的空格:#160;#160;#8201;,用两个空格(#160;#160;)占一个汉字的宽度时,两个空格比一个汉字略窄,三个空格(#160;#160;#160;)比一个汉字略宽 在实际使用中需要灵活使用#160;和#8201;的组合。 android:text=”真实姓名:” android:text=”身 份 证:” android:text=”姓 ‒名:” android:text=”身份证:” #8194;半个中文字更准确点, #8195;一个中文字但用起来会比中文字宽一点点。 所以中文对齐还是建议使用#8194;, 而#160; #8201;在不同机型有不同表现。 TextView实现首行缩进的方法: 在string资源文件中,在文字的前面加入”\u3000\u3000”即可实现首行缩进 在Java代码中,使用setText(“\u3000\u3000”+xxxxx); \u3000是全角空格的16进制Unicode编码。 \xa0代表 转自:http://blog.csdn.net/u014651216/article/details/52411113

2017年10月17日 · 1 分钟 · 天边的星星

android textview 自动换行 整齐排版

一、问题在哪里? textview显示长文字时会进行自动折行,如果遇到一些特殊情况,自动折行会杯具成这个样子: 上述特殊情况包括: 1)全角/半角符号混排(一般是数字、字母、汉字混排) 2)全角/半角标点符号出现在行首时,该标点符号会连同其前一个字符跳到下一行 3)英文单词不能被折成两行 4)…… 二、怎么搞? 通常有两类解决方案: 1)修改文本内容,将所有符号全角化、在标点符号前面加空格等等…… 2)保持文本内容不变,在合适的位置将文本手动分成多行 本文采用第二种方案,更加通用,也最大限度的保留了原文本。 三、开始干活 3.1 “在合适的位置将文本手动分成多行”需要知道textview的实际宽度、字体大小等信息,框架如下: ![复制代码](http://common.cnblogs.com/images/copycode.gif) 1 public class TestCActivity extends Activity { 2 private TextView mText; 3 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 8 setContentView(R.layout.testc); 9 10 mText = (TextView)findViewById(R.id.txt); 11 mText.setText("本文地址http://www.cnblogs.com/goagent/p/5159125.html本文地址啊本文。地址。啊http://www.cnblogs.com/goagent/p/5159125.html"); 12 mText.getViewTreeObserver().addOnGlobalLayoutListener(new OnTvGlobalLayoutListener()); 13 } 14 15 private class OnTvGlobalLayoutListener implements OnGlobalLayoutListener { 16 @Override 17 public void onGlobalLayout() { 18 mText.getViewTreeObserver().removeOnGlobalLayoutListener(this); 19 final String newText = autoSplitText(mText); 20 if (!TextUtils.isEmpty(newText)) { 21 mText.setText(newText); 22 } 23 } 24 } 25 26 private String autoSplitText(final TextView tv) { 27 final String rawText = tv.getText().toString(); 28 final Paint tvPaint = tv.getPaint(); 29 final int tvWidth = tv.getWidth() - tv.getPaddingLeft() - tv.getPaddingRight(); 30 31 //autoSplitText begin.... 32 String newText = rawText; 33 //autoSplitText end.... 34 35 return newText; 36 } 37 } ![复制代码](http://common.cnblogs.com/images/copycode.gif) 3.2 实现自动分割文本,简单来说就是用textview的paint逐字符测量,如果发现当前行绘制不下了,就手动加入一个换行符: ...

2017年10月16日 · 6 分钟 · 天边的星星

Android动态获取权限

前几天在网上找了找Android动态获取权限的文章和视频,自己整理了一下。几天看一位大神说真正的程序员是有着分享精神的,我这个刚刚入行的小菜鸟,也想把自己整理的东西分享给大家。 本文参考了A_si的Permission——郭霖认为最优的运行时权限方案和郭霖大神的CSDN视屏 在这之前,我们需要知道什么是权限? 权限是一种安全机制。Android权限主要用于限制应用程序内部某些具有限制性特性的功能使用以及应用程序之间的组件访问。 比如网络权限 " data-snippet-id="ext.1ecd4ff36f58d5c42638b9d887b68988" data-snippet-saved="false" data-codota-status="done">&lt;user-permission android:name="android.permission.INTERNET"/&gt;当我们的程序需要访问网络的时候,必须添加这个权限,不添加则无法访问网络。 这里还需要注意的是:在Android6.0之前,我们只需要在AndroidManifest.xml文件中直接添加权限即可,但是在Android6.0之后,我们只在AndroidManifest.xml文件中配置是不够的,还需要在Java代码中进行动态获取权限。当然这里不是所有的权限都需要动态获取,只需要获取危险权限就可以了。(毕竟Android权限100多种,要是每个都需要获取,那不累死开发人员啦) Android中的危险权限分为9组24种 ![](http://upload-images.jianshu.io/upload_images/3780051-92dda32c577e32cb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 1454742-2c2196fd438a4ed3.png 我们只需要在用这些权限的时候,才需要去动态申请,除这些之外的权限,我们只需要在AndroidManifest.xml文件种写上即可,动态申请的权限同样需要在AndroidManifest.xml文件中写。而且每一组种的权限只要有一个授权了,其他的也会自动授权 下面这张图是我们的build.gradle文件中的版本信息 ![](http://upload-images.jianshu.io/upload_images/3780051-e00a73adfc0a922a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) Image.png 1、targetSdkVersion版本号如果<= 21时,不需要动态处理权限 。但是有时候我们的应用程序会打不开。 2、如果是之前的老版本升级上来的,系统会默认开启之前所有的权限,比如之前的targetSdkVersion是21,后来升级之后变成了25,这个时候系统会自动授权。一定要记住是升级变成的25,否则还是需要授权。 Tips: 为什么SD卡读写权限是危险权限,能不能不申请权限但又能使用SD卡呢? (1)把SD权限设置为危险权限,是为了防止应用随便在用户的手机上些东西,如果不加防范,用户的SD卡就会有很多乱七八糟的东西。 (2)用户可以不申请权限而使用SD卡,但是只能使用系统提供的默认的路径。 我们可以使用Android系统提供的SDK目录。路径是Android\data\程序包名。这个目录是程序可以不需要经过 用户授权就可以直接使用,甚至不需要添加WRITE_EXTERNAL_STORAGE这个权限。 这个目录会在程序删除时也会直接删除。 如何访问这个目录呢? File file = getExternalCacheDir(); String s = file.getPath; 这个方法得到的是cache的路径,但是一般的垃圾清理软件都可以把这里面的数据清理掉 File[] files = getExternalCacheDirs(); 这个得到的是一个文件数组,要求Api最小19 如果我们不想垃圾清理软件把我们缓存的数据清理掉,则可以放在file文件下 getExternalFilesDir(“”); 这个表示所有的操作都是放在file目录下进行的 getExternalFilesDir(“mm”); 这个表示会在file目录下在见一个mm目录,然后所有的操作都会放在这个目录下。 下面我们来看如何动态获取权限!!! 先看最简单的,动态获取一个权限 比如现在要动态获取一个打电话的权限。。 首先需要在AndroidManifest.xml文件中写上这个权限 " data-snippet-id="ext.f281d8d8d9cfe2d283d570842a2b4c1e" data-snippet-saved="false" data-codota-status="done">&lt;user-permission android:name="android.premission.CALL_PHONE"/&gt; 然后在Java代码进行动态获取 请求授权的代码 ` &lt;span class="hljs-comment">/** * 请求授权 */&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">private&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">requestPermission&lt;/span>&lt;span class="hljs-params">()&lt;/span>&lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (ContextCompat.checkSelfPermission(&lt;span class="hljs-keyword">this&lt;/span>, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){ &lt;span class="hljs-comment">//表示未授权时&lt;/span> &lt;span class="hljs-comment">//进行授权&lt;/span> ActivityCompat.requestPermissions(&lt;span class="hljs-keyword">this&lt;/span>,&lt;span class="hljs-keyword">new&lt;/span> String[]{Manifest.permission.CALL_PHONE},&lt;span class="hljs-number">1&lt;/span>); }&lt;span class="hljs-keyword">else&lt;/span>{ &lt;span class="hljs-comment">//调用打电话的方法&lt;/span> makeCall(); } }` 请求之后,我们需要重写onRequestPermissionsResult这个方法 ...

2017年10月11日 · 8 分钟 · 天边的星星

Android apk反编译及重新打包流程

### 一、反编译代码 **1、**反编译java代码首先需要下载**dex2jar**这个工具,下载地址:[https://sourceforge.net/projects/dex2jar/files/](https://sourceforge.net/projects/dex2jar/files/) 目前最新版是2.0, 下载完后并解压缩。 2、将要反编译的apk文件重命名为zip格式并解压缩,注意其中的classes.dex文件,它存放了全部的java代码,将classes.dex文件拷贝到dex2jar解压后的根目录下。 **3、**打开cmd,进入dex2jar解压后的根目录,执行命令: ** d2j-dex2jar classes.dex 如下图: ![](http://upload-images.jianshu.io/upload_images/1633070-6fc5febd3f11a9ef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> dex2jar </div> 命令执行完后在对应目录下会生成<strong>classes-dex2jar.jar**文件 ![](http://upload-images.jianshu.io/upload_images/1633070-ba7fc87bb47cc64e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> jar文件 </div> **4、**要查看java代码,还需要下载**jd-gui**这个工具,下载地址:[http://jd.benow.ca/](http://jd.benow.ca/),目前最新版是1.4.0,下载完后解压缩,并用**jd-gui.exe**打开上边反编译出来的jar文件: ![](http://upload-images.jianshu.io/upload_images/1633070-3bb77b39750f7562.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> java code </div> 到此,已经顺利的反编译出了java代码 那资源文件呢,再回头看一下刚才apk文件对应的解压缩文件,所有的xml文件都是乱码,例如AndroidManifest.xml: ![](http://upload-images.jianshu.io/upload_images/1633070-2e019b033641d4d3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> AndroidManifest.xml </div> 当然要还原原始的资源文件还是有办法的,继续往下看。 二、反编译资源 **1、**要反编译apk中的资源文件,就需要**apktool**这个工具了,下载地址:[http://ibotpeaches.github.io/Apktool/install/](http://ibotpeaches.github.io/Apktool/install/),进入下载页面: ![](http://upload-images.jianshu.io/upload_images/1633070-6715ef0d87edee56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> apktool download </div> 按照图中1、2两条的提示,下载**apktool.bat和apktool.jar**这两个文件,目前最新的apktool是2.1.1,并放到同一文件夹: ![](http://upload-images.jianshu.io/upload_images/1633070-e6e8d64f3519b021.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <div class="image-caption"> apktool </div> , **2、**将要反编译的apk文件放到apktool文件夹,打开cmd,进入apktool文件夹目录,执行命令: ...

2017年10月11日 · 2 分钟 · 天边的星星

Android java.security.NoSuchProviderException: no such provider: Crypto

由于项目的优化改进,用到AES+RSA加密传输数据。于是,在网上摘录了网友们的AES算法,如下: **public static byte**[] encrypt(**byte**[] raw, **byte**[] clear) **throws **Exception { SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **"AES"**); Cipher cipher = Cipher.getInstance(**"AES"**); cipher.init(Cipher.***ENCRYPT_MODE***, skeySpec); **byte**[] encrypted = cipher.doFinal(clear); **return **encrypted; } **public static byte**[] decrypt(**byte**[] raw, **byte**[] encrypted) **throws **Exception { SecretKeySpec skeySpec = **new **SecretKeySpec(raw, **"AES"**); Cipher cipher = Cipher.getInstance(**"AES"**); cipher.init(Cipher.***DECRYPT_MODE***, skeySpec); **byte**[] decrypted = cipher.doFinal(encrypted); **return **decrypted; } **public static byte**[] getRawKey(**byte**[] seed) **throws **Exception { KeyGenerator kgen = KeyGenerator.getInstance(**"AES"**); SecureRandom sr = SecureRandom.getInstance(**"SHA1PRNG"**, **"Crypto"**); sr.setSeed(seed); kgen.init(128, sr); SecretKey skey = kgen.generateKey(); **byte**[] raw = skey.getEncoded(); **return **raw; } 一切正常的在Android 4.3-6.1的手机上加解密,但是我用 *LGE Nexus 5X (7.1.1 API 25)*上发现在Android N上 google去掉了**Crypto **provider,意味着我们将不能继续像上面那样对数据加密填充。当然,在studio里的Logcat里会提示前往关于Android N对Crypto的解决方案: http://Android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html ...

2017年9月5日 · 2 分钟 · 天边的星星

Android 使用ViewPager实现类似gallery画廊的效果(画廊效果之ViewPager显示多个图片)

这个画廊的效果利用到了View的clipChildren属性,我们在这里要把ViewPager以及它的父窗体都设置为false,如下: Android:clipChildren=”false” 因为如果clipChildren属性设置为true,就表明我们要将children给clip掉,就是说对于子元素来说,超出当前view的部分都会被切掉,那我们在这里把它设置成false,就表明超出view的部分,不要切掉,依然显示。 xml代码部分: <LinearLayout android:id=”@+id/container” android:layout_width=”match_parent” android:layout_height=”100dp” android:clipChildren=”false” android:gravity=”center_horizontal” android:layerType=”software” android:orientation=”horizontal” > <android.support.v4.view.ViewPager android:id=”@+id/viewpager” android:layout_width=”match_parent” android:layout_height=”match_parent” android:layout_marginLeft=”110dp” android:layout_marginRight=”110dp” android:clipChildren=”false” > </android.support.v4.view.ViewPager> Java代码部分: // 1.设置幕后item的缓存数目 mViewPager.setOffscreenPageLimit(3); // 2.设置页与页之间的间距 mViewPager.setPageMargin(10); // 3.将父类的touch事件分发至viewPgaer,否则只能滑动中间的一个view对象 container.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return mViewPager.dispatchTouchEvent(event); } }); 参考效果图(上面代码并不能实现效果图,仅供参考): 正常情况下, ViewPager 一页只能显示一项数据, 但是如果需求是, 除了小显示本页数据, 还有包 左右两半的数据 也都露出一点来呢? 这该怎么处理? 后面在网上了搜了一下, 发现有不少这样得到文章, 这里自己也写一篇总结一下. 其实 主要就是用到 View 的 android:clipChildren 属性. 简单来说这个属性, 就是 父View 是否 束缚 子View 的显示范围. 如果 父View 有 padding , 那么 子View 则在 padding区域是不能显示内容的, 但是如果 设置 android:clipChildren 为 false 时, 则子View 就可以在 父View 的padding屈戌显示内容了. ok 基本了解了 android:clipChildren 那么来处理一下 ViewPager吧 先看一下我做的demo: ...

2017年8月29日 · 2 分钟 · 天边的星星

Android ToolBar 使用完全解析

ToolBar简介 ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar,由于其高度的可定制性、灵活性、具有Material Design风格等优点,越来越多的应用也用上了ToolBar,比如常用的知乎软件其顶部导航栏正是使用ToolBar。官方考虑到仍有一部分用户的手机版本号低于5.0,所以,ToolBar也放进了support v7包内,使得低版本的系统也能使用上ToolBar。本文将使用support v7支持包的ToolBar来进行讲解,包括其基本用法、样式定制等知识点。 ToolBar的基本使用 引入support v7支持包 在你项目的build.gradle内输入如下代码,即能引入支持包,该支持包内有能向下兼容的ToolBar: `dependencies { compile fileTree(dir: &lt;span class="hljs-string">'libs'&lt;/span>, include: [&lt;span class="hljs-string">'*.jar'&lt;/span>]) compile &lt;span class="hljs-string">'com.android.support:appcompat-v7:23.1.1'&lt;/span> }`<a target="_blank" name="t3"></a> 更改主题 为了能够正常使用ToolBar,我们需要隐藏原来的ActionBar,这个可以在主题中修改,在values/styles.xml中做出如下修改: " width="20" data-original-code="![]( data-wp-preserve=)1 2 1 2 " data-snippet-id="ext.2bc0da59d9ff7d2cc4639972565d3679" data-snippet-saved="false" data-codota-status="done" style="white-space: nowrap; word-wrap: break-word; box-sizing: border-box; position: relative; overflow-y: hidden; overflow-x: auto; margin: 0px 0px 1.1em; font-family: "Source Code Pro", monospace; display: block; padding: 5px 5px 5px 60px; font-size: 14px; line-height: 1.45; word-break: break-all; color: rgb(51, 51, 51); background-color: rgba(128, 128, 128, 0.05); border: 0px solid rgb(136, 136, 136); border-radius: 0px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"&gt;`&lt;span class="hljs-tag">&lt;&lt;span class="hljs-title">style&lt;/span> &lt;span class="hljs-attribute">name&lt;/span>=&lt;span class="hljs-value">"AppTheme"&lt;/span> &lt;span class="hljs-attribute">parent&lt;/span>=&lt;span class="hljs-value">"Theme.AppCompat.Light.NoActionBar"&lt;/span>&gt;&lt;/span> &lt;span class="hljs-tag">&lt;/&lt;span class="hljs-title">style&lt;/span>&gt;&lt;/span>` 继承了Theme.Appcompat.Light.NoActionBar主题,这里提一下,这个Theme.AppCompat是支持包内的主题,对应着5.0版本的Theme.Material主题。然后在manifest文件中引用这个主题。 ...

2017年8月26日 · 6 分钟 · 天边的星星

新布局节点ConstraintLayout基本使用

Android ConstraintLayout详解 AndroidStudio2.2开始,就推出了一个牛逼的布局,ConstraintLayout,此布局像是一个升级版的RelativeLayout,但是功能比RelativeLayout强大许多,号称一层布局就可以搞定复杂页面。在AS2.2下还可以用拖拽控件的方式就行布局(设计师的福音),不过本篇不讲解拖拽控件的相关用法,主要讲解一些相关属性含义。 想学习拖拽控件设计ConstraintLayout的请点这里。 Android官方教程在此。 本文讲解参考这里,需自备梯子。 开始! 相对位置这个相对位置的设置有点类似RelativeLayout的layout_toLeftOf、alignParentLeft等这些属性。 ConstraintLayout一共支持相对位置的属性在此: layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintTop_toTopOf layout_constraintTop_toBottomOf layout_constraintBottom_toTopOf layout_constraintBottom_toBottomOf layout_constraintBaseline_toBaselineOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintEnd_toStartOf layout_constraintEnd_toEndOf拿第一个属性来说,layout_constraintLeft_toLeftOf=”@+id/id_first”,表示当前View的左边界与id_first的View的做边界对齐。其实这个属性翻译成中文就是:当前view的左边对齐与引用view的左边。 例子: <Button android:id=&quot;@+id/buttonB&quot; ... app:layout_constraintLeft_toRightOf=&quot;@+id/buttonA&quot; />1 2 3 1 2 3 1 2 3 1 2 3 " data-snippet-id="ext.3190b6ad748f0e96e5cbd62a084f67f5" data-snippet-saved="false" data-codota-status="done">`&lt;Button android:id=&lt;span class="hljs-string">"@+id/buttonA"&lt;/span> &lt;span class="hljs-keyword">...&lt;/span> /&gt; &lt;Button android:id=&lt;span class="hljs-string">"@+id/buttonB"&lt;/span> &lt;span class="hljs-keyword">...&lt;/span> app:layout_constraintLeft_toRightOf=&lt;span class="hljs-string">"@+id/buttonA"&lt;/span> /&gt;` 效果如下: 当然,这些属性也支持设置为对齐父布局的左右前后。 1 2 1 2 1 2 1 2 " data-snippet-id="ext.66574d68fbfbe560220fafc526a7805f" data-snippet-saved="false" data-codota-status="done">`&lt;Button android:id=&lt;span class="hljs-string">"@+id/buttonB"&lt;/span> &lt;span class="hljs-keyword">...&lt;/span> app:layout_constraintLeft_toLeftOf=&lt;span class="hljs-string">"parent"&lt;/span> /&gt;` 这样,buttonB就依附在父布局的左边。类似Realitelayout的alignParentLeft。 margin属性这个属性没啥好说的,跟其他布局的margin属性差不多。支持的属性如下: Android:layout_marginStart android:layout_marginEnd android:layout_marginLeft android:layout_marginTop android:layout_marginRight android:layout_marginBottom 注意:如上图,假如A紧贴父布局的左侧,B距离A 100dp,A设置为gone后,则B距离父布局的左侧100dp。 goneMargin属性这个布局比较有意思,还是拿上面的那副图做示例,假设我们现在有这样一个需求:假设A设置为gone,后,B需要距离父布局的左侧200dp,怎么办?这时候,goneMargin属性就派上用场啦,只要设置B的layout_goneMarginLeft=200dp即可。这样,A不为gone的时候,B距离A 100dp,A为gone时,B距离父布局左侧200dp。 一共支持的属性如下: layout_goneMarginStart layout_goneMarginEnd layout_goneMarginLeft layout_goneMarginTop layout_goneMarginRight layout_goneMarginBottom Centering positioning and bias ,设置居中或者按比例偏移。 假设我们要设置一个控件居中怎么办?很简单,利用上面介绍过的属性就可以办到。 <Button android:id=&quot;@+id/button&quot; ... app:layout_constraintHorizontal_bias=&quot;0.3&quot; app:layout_constraintLeft_toLeftOf=&quot;parent&quot; app:layout_constraintRight_toRightOf=&quot;parent/> </>1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 " data-snippet-id="ext.fa91acc62f5d2da7b193dcfae6657c0a" data-snippet-saved="false" data-codota-status="done">` &lt;android.support.constraint.ConstraintLayout &lt;span class="hljs-keyword">...&lt;/span>&gt; &lt;Button android:id=&lt;span class="hljs-string">"@+id/button"&lt;/span> &lt;span class="hljs-keyword">...&lt;/span> app:layout_constraintHorizontal_bias=&lt;span class="hljs-string">"0.3"&lt;/span> app:layout_constraintLeft_toLeftOf=&lt;span class="hljs-string">"parent"&lt;/span> app:layout_constraintRight_toRightOf=&lt;span class="hljs-string">"parent/&gt; &lt;/&gt;&lt;/span>` bias支持的属性如下: layout_constraintHorizontal_bias layout_constraintVertical_bias ...

2017年6月29日 · 3 分钟 · 天边的星星

Android RecyclerView 使用完全解析 体验艺术般的控件

概述 RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。 那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。 你想要控制其显示的方式,请通过布局管理器LayoutManager 你想要控制Item间的间隔(可绘制),请通过ItemDecoration 你想要控制Item增删的动画,请通过ItemAnimator 你想要控制点击、长按事件,请自己写(擦,这点尼玛。) 基本使用 鉴于我们对于ListView的使用特别的熟悉,对比下RecyclerView的使用代码: `mRecyclerView = findView(R.id.id_recyclerview); &lt;span class="hljs-comment">//设置布局管理器&lt;/span> mRecyclerView.setLayoutManager(layout); &lt;span class="hljs-comment">//设置adapter&lt;/span> mRecyclerView.setAdapter(adapter) &lt;span class="hljs-comment">//设置Item增加、移除动画&lt;/span> mRecyclerView.setItemAnimator(&lt;span class="hljs-keyword">new&lt;/span> DefaultItemAnimator()); &lt;span class="hljs-comment">//添加分割线&lt;/span> mRecyclerView.addItemDecoration(&lt;span class="hljs-keyword">new&lt;/span> DividerItemDecoration( getActivity(), DividerItemDecoration.HORIZONTAL_LIST));` ok,相比较于ListView的代码,ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤,那么为什么会添加这么多的步骤呢? 那么就必须解释下RecyclerView的这个名字了,从它类名上看,RecyclerView代表的意义是,我只管Recycler View,也就是说RecyclerView只管回收与复用View,其他的你可以自己去设置。可以看出其高度的解耦,给予你充分的定制自由(所以你才可以轻松的通过这个控件实现ListView,GirdView,瀑布流等效果)。 Just like ListView Activity `&lt;span class="hljs-keyword">package&lt;/span> com.zhy.sample.demo_recyclerview; &lt;span class="hljs-keyword">import&lt;/span> java.util.ArrayList; &lt;span class="hljs-keyword">import&lt;/span> java.util.List; &lt;span class="hljs-keyword">import&lt;/span> android.os.Bundle; &lt;span class="hljs-keyword">import&lt;/span> android.support.v7.app.ActionBarActivity; &lt;span class="hljs-keyword">import&lt;/span> android.support.v7.widget.LinearLayoutManager; &lt;span class="hljs-keyword">import&lt;/span> android.support.v7.widget.RecyclerView; &lt;span class="hljs-keyword">import&lt;/span> android.support.v7.widget.RecyclerView.ViewHolder; &lt;span class="hljs-keyword">import&lt;/span> android.view.LayoutInflater; &lt;span class="hljs-keyword">import&lt;/span> android.view.View; &lt;span class="hljs-keyword">import&lt;/span> android.view.ViewGroup; &lt;span class="hljs-keyword">import&lt;/span> android.widget.TextView; &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-class">&lt;span class="hljs-keyword">class&lt;/span> &lt;span class="hljs-title">HomeActivity&lt;/span> &lt;span class="hljs-keyword">extends&lt;/span> &lt;span class="hljs-title">ActionBarActivity&lt;/span> {&lt;/span> &lt;span class="hljs-keyword">private&lt;/span> RecyclerView mRecyclerView; &lt;span class="hljs-keyword">private&lt;/span> List&lt;String&gt; mDatas; &lt;span class="hljs-keyword">private&lt;/span> HomeAdapter mAdapter; &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">protected&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onCreate&lt;/span>(Bundle savedInstanceState) { &lt;span class="hljs-keyword">super&lt;/span>.onCreate(savedInstanceState); setContentView(R.layout.activity_single_recyclerview); initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mRecyclerView.setLayoutManager(&lt;span class="hljs-keyword">new&lt;/span> LinearLayoutManager(&lt;span class="hljs-keyword">this&lt;/span>)); mRecyclerView.setAdapter(mAdapter = &lt;span class="hljs-keyword">new&lt;/span> HomeAdapter()); } &lt;span class="hljs-keyword">protected&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">initData&lt;/span>() { mDatas = &lt;span class="hljs-keyword">new&lt;/span> ArrayList&lt;String&gt;(); &lt;span class="hljs-keyword">for&lt;/span> (&lt;span class="hljs-keyword">int&lt;/span> i = &lt;span class="hljs-string">'A'&lt;/span>; i &lt; &lt;span class="hljs-string">'z'&lt;/span>; i++) { mDatas.add(&lt;span class="hljs-string">""&lt;/span> + (&lt;span class="hljs-keyword">char&lt;/span>) i); } } class HomeAdapter extends RecyclerView.Adapter&lt;HomeAdapter.MyViewHolder&gt; { &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> MyViewHolder &lt;span class="hljs-title">onCreateViewHolder&lt;/span>(ViewGroup parent, &lt;span class="hljs-keyword">int&lt;/span> viewType) { MyViewHolder holder = &lt;span class="hljs-keyword">new&lt;/span> MyViewHolder(LayoutInflater.from( HomeActivity.&lt;span class="hljs-keyword">this&lt;/span>).inflate(R.layout.item_home, parent, &lt;span class="hljs-keyword">false&lt;/span>)); &lt;span class="hljs-keyword">return&lt;/span> holder; } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onBindViewHolder&lt;/span>(MyViewHolder holder, &lt;span class="hljs-keyword">int&lt;/span> position) { holder.tv.setText(mDatas.get(position)); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">int&lt;/span> &lt;span class="hljs-title">getItemCount&lt;/span>() { &lt;span class="hljs-keyword">return&lt;/span> mDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv; &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-title">MyViewHolder&lt;/span>(View view) { &lt;span class="hljs-keyword">super&lt;/span>(view); tv = (TextView) view.findViewById(R.id.id_num); } } } }` Activity的布局文件 `&lt;span class="hljs-tag">&lt;&lt;span class="hljs-title">RelativeLayout&lt;/span> &lt;span class="hljs-attribute">xmlns:android&lt;/span>=&lt;span class="hljs-value">"http://schemas.android.com/apk/res/android"&lt;/span> &lt;span class="hljs-attribute">xmlns:tools&lt;/span>=&lt;span class="hljs-value">"http://schemas.android.com/tools"&lt;/span> &lt;span class="hljs-attribute">android:layout_width&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> &lt;span class="hljs-attribute">android:layout_height&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> &gt;&lt;/span> &lt;span class="hljs-tag">&lt;&lt;span class="hljs-title">android.support.v7.widget.RecyclerView &lt;/span> &lt;span class="hljs-attribute">android:id&lt;/span>=&lt;span class="hljs-value">"@+id/id_recyclerview"&lt;/span> &lt;span class="hljs-attribute">android:divider&lt;/span>=&lt;span class="hljs-value">"#ffff0000"&lt;/span> &lt;span class="hljs-attribute">android:dividerHeight&lt;/span>=&lt;span class="hljs-value">"10dp"&lt;/span> &lt;span class="hljs-attribute">android:layout_width&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> &lt;span class="hljs-attribute">android:layout_height&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> /&gt;&lt;/span> &lt;span class="hljs-tag">&lt;/&lt;span class="hljs-title">RelativeLayout&lt;/span>&gt;&lt;/span>` Item的布局文件 `&lt;span class="hljs-pi">&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;/span> &lt;span class="hljs-tag">&lt;&lt;span class="hljs-title">FrameLayout&lt;/span> &lt;span class="hljs-attribute">xmlns:android&lt;/span>=&lt;span class="hljs-value">"http://schemas.android.com/apk/res/android"&lt;/span> &lt;span class="hljs-attribute">android:layout_width&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> &lt;span class="hljs-attribute">android:background&lt;/span>=&lt;span class="hljs-value">"#44ff0000"&lt;/span> &lt;span class="hljs-attribute">android:layout_height&lt;/span>=&lt;span class="hljs-value">"wrap_content"&lt;/span> &gt;&lt;/span> &lt;span class="hljs-tag">&lt;&lt;span class="hljs-title">TextView &lt;/span> &lt;span class="hljs-attribute">android:id&lt;/span>=&lt;span class="hljs-value">"@+id/id_num"&lt;/span> &lt;span class="hljs-attribute">android:layout_width&lt;/span>=&lt;span class="hljs-value">"match_parent"&lt;/span> &lt;span class="hljs-attribute">android:layout_height&lt;/span>=&lt;span class="hljs-value">"50dp"&lt;/span> &lt;span class="hljs-attribute">android:gravity&lt;/span>=&lt;span class="hljs-value">"center"&lt;/span> &lt;span class="hljs-attribute">android:text&lt;/span>=&lt;span class="hljs-value">"1"&lt;/span> /&gt;&lt;/span> &lt;span class="hljs-tag">&lt;/&lt;span class="hljs-title">FrameLayout&lt;/span>&gt;&lt;/span>` 这么看起来用法与ListView的代码基本一致哈~~ 看下效果图: ...

2017年6月20日 · 15 分钟 · 天边的星星