android瀑布流 怎么实现 逆向瀑布流

&Android实现不规则瀑布流效果
秒后自动跳转到登录页
快捷登录:
举报类型:
不规范:上传重复资源
不规范:标题与实际内容不符
不规范:资源无法下载或使用
其他不规范行为
违规:资源涉及侵权
违规:含有危害国家安全等内容
违规:含有反动/色情等内容
违规:广告内容
详细原因:
任何违反下载中心规定的资源,欢迎Down友监督举报,第一举报人可获5-10下载豆奖励。
视频课程推荐
Android实现不规则瀑布流效果
上传时间:
技术分类:
资源评价:
(0位用户参与评价)
已被下载&4&次
Android实现不规则瀑布流效果,实用
本资料共包含以下附件:
Android实现不规则瀑布流效果.zip
51CTO下载中心常见问题:
1.如何获得下载豆?
1)上传资料
2)评论资料
3)每天在首页签到领取
4)购买VIP会员服务,无需下载豆下载资源
5)更多途径:点击此处
2.如何删除自己的资料?
下载资料意味着您已同意遵守以下协议:
1.资料的所有权益归上传用户所有
2.未经权益所有人同意,不得将资料中的内容挪作商业或盈利用途
3.51CTO下载中心仅提供资料交流平台,并不对任何资料负责
4.本站资料中如有侵权或不适当内容,请邮件与我们联系()
5.本站不保证资源的准确性、安全性和完整性, 同时也不承担用户因使用这些资料对自己和他人造成任何形式的伤害或损失
相关专题推荐
Google正式在Android官网发布Android
本套视频教程专为希望成为Android开发
本专题收集了android开发的一系列小工
Android目前已经占据了全球智能手机操
本套视频是传智播客3G-Android就业班
本专题精选了Android开发相关的电子书
本专题视频共有67集,是传智播客3G-A
安卓移动平台自2007年11月开放源码以
本课程使用Android 2.3.3平台进行开发
此视频实战内容由浅入深,从游戏开发
新浪微博Android客户端开发视频教程是
本视频由黑马程序员的张泽华老师录制
一大波Android源码来袭。本专题为And
本专题为张泽华老师教授的Android开发
UI设计则是指对软件的人机交互、操作
OpenGL ES (OpenGL for Embedded Sys
意见或建议:
联系方式:
您已提交成功!感谢您的宝贵意见,我们会尽快处理37154人阅读
android UI(常用)(66)
& & 自pinterest使用了瀑布流展示图片后,有很多应用开始使用瀑布流的方式,像蘑菇街,美丽说。这里的瀑布流实现使用了开源代码。layout:&?xml version=&1.0& encoding=&utf-8&?&
&com.dodowaterfall.LazyScrollView xmlns:android=&/apk/res/android&
& & android:layout_width=&fill_parent&
& & android:layout_height=&fill_parent&
& android:id=&@+id/waterfall_scroll&
& android:scrollbars=&vertical&
& & &LinearLayout
& & & & android:id=&@+id/waterfall_container&
& & & & android:layout_width=&fill_parent&
& & & & android:layout_height=&fill_parent&
& & & & android:background=&@android:color/white&&
& & &/LinearLayout&
&/com.dodowaterfall.LazyScrollView&
& &整个瀑布流用的是ScrollView的子类LazyScrollView。这个LazyScrollView中设置了一个监听器接口,用来监听ScrollView执行的不同阶段。接口如下:public interface OnScrollListener {
void onBottom();
void onTop();
void onScroll();
void onAutoScroll(int l, int t, int oldl, int oldt);
}& & 对于每一幅图,都用一个ImageView的子类FlowView来表示。为了不阻塞UI线程,图片加载和图片更新都分别用不同的线程来做。这两个线程都在FlowView中。FlowView提供了加载和更新的接口给Activity调用。瀑布流实例的主Activity是MainActivity,常量都保存在Constants类中,方便维护。& & 瀑布流最重要的是图片的内存回收机制,防止发生内存溢出的情况(OOM)。参考:/*** @author 张兴业* 邮箱:* android开发进阶群:**/
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:5433728次
积分:39964
积分:39964
排名:第88名
原创:273篇
转载:195篇
译文:20篇
评论:1902条
android 开发交流
济南移动互联网:
文章:10篇
阅读:459706
文章:18篇
阅读:601030
阅读:116231
文章:11篇
阅读:149039
文章:13篇
阅读:271157
文章:59篇
阅读:1716471
(1)(1)(2)(2)(1)(2)(4)(2)(3)(1)(2)(6)(1)(6)(4)(11)(3)(1)(7)(7)(7)(4)(5)(1)(1)(5)(1)(10)(11)(7)(5)(1)(2)(1)(8)(4)(4)(8)(23)(23)(1)(1)(1)(3)(9)(15)(34)(11)(5)(3)(3)(1)(5)(2)(5)(14)(23)(22)(25)(46)(7)(9)(30)(8)(1)(5)(1)参考:/p/cb早期的Android系统几乎只支持ARMv5的CPU架构,你知道现在它支持多少种吗?Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。应用程序二进制接口ABI(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。为什么你需要重点关注.so文件项目中使用到了NDK,它将会生成.so文件。如果只使用Java语言进行编码,你可能在想不需要关注.so文件了吧,因为Java是跨平台的。但你可能并没有意识到项目中依赖的函数库或者引擎库里面已经嵌入了.so文件,并依赖于不同的ABI。Android应用支持的ABI取决于APK中位于lib/ABI目录中的.so文件,其中ABI可能是上面说过的七种ABI中的一种。本地库监视器Native Libs Monitor这个应用可以帮助我们理解手机上安装的APK用到了哪些.so文件,以及.so文件来源于哪些函数库或者框架。ABI和CPU的关系很多设备都支持多于一种的ABI。当一个应用安装在设备上,只有该设备支持的CPU架构对应的.so文件会被安装。但最好是针对特定平台提供相应平台的二进制包,这种情况下运行时就少了一个模拟层(例如x86设备上模拟arm的虚拟层),从而得到更好的性能(归功于最近的架构更新,例如硬件fpu,更多的寄存器,更好的向量化等)。我们可以通过Build.SUPPORTED_ABIS得到根据偏好排序的设备支持的ABI列表。但你不应该从你的应用程序中读取它,因为Android包管理器安装APK时,会自动选择APK包中为对应系统ABI预编译好的.so文件,如果在对应的lib/ABI目录中存在.so文件的话。ABI(横向)和cpu(纵向)armeabiarmeabi-v7aarm64-v8amipsmips64x86x86_64ARMv5支持ARMv7支持支持ARMv8支持支持支持MIPS支持MIPS64支持支持x86支持(3)支持(2)支持(1)x86_64支持支持支持解析: x86设备上,libs/x86目录中如果存在.so文件的话,会被安装,如果不存在,则会选择armeabi-v7a中的.so文件,如果也不存在,则选择armeabi目录中的.so文件。x86设备能够很好的运行ARM类型函数库,但并不保证100%不发生crash,特别是对旧设备。64位设备(arm64-v8a, x86_64, mips64)能够运行32位的函数库,但是以32位模式运行,在64位平台上运行32位版本的ART和Android组件,将丢失专为64位优化过的性能(ART,webview,media等等)。.so文件重要法则处理.so文件时有一条简单却并不知名的重要法则。你应该尽可能的提供专为每个ABI优化过的.so文件,但要么全部支持,要么都不支持:你不应该混合着使用。你应该为每个ABI目录提供对应的.so文件。NDK兼容性使用NDK时,你可能会倾向于使用最新的编译平台,但事实上这是错误的,因为NDK平台不是后向兼容(兼容过去的版本)的,而是前向兼容(兼容将来的版本)的。推荐使用app的minSdkVersion对应的编译平台。这也意味着当你引入一个预编译好的.so文件时,你需要检查它被编译所用的平台版本。混合使用不同C++运行时编译的.so文件.so文件可以依赖于不同的C++运行时,静态编译或者动态加载。
混合使用不同版本的C++运行时可能导致很多奇怪的crash,是应该避免的。一个经验法则当只有一个.so文件时,静态编译C++运行时是没问题的,当存在多个.so文件时,应该让所有的.so文件都动态链接相同的C++运行时。这意味着当引入一个新的预编译.so文件,而且项目中还存在其他的.so文件时,我们需要首先确认新引入的.so文件使用的C++运行时是否和已经存在的.so文件一致。。关于.so文件的错误示例问题:
你的app目前只支持armeabi-v7a和x86架构,你想让app支持更多的cpu类型,新增了一个函数库依赖,这个函数库包含.so文件并支持更多的CPU架构。发布我们的app后,会发现它在某些设备上会发生Crash,例如Galaxy S6,最终可以发现只有64位目录下的.so文件被安装进手机。解决方案:重新编译我们的.so文件使其支持缺失的ABIs也可以设置ndk.abiFilters显示指定支持的ABIs.so文件的路径拓展:http://blog.csdn.net/xx/article/details/在IDE中的路径Android Studio工程放在jniLibs/ABI目录中(当然也可以通过在build.gradle文件中的设置jniLibs.srcDir属性自己指定)Eclipse工程放在libs/ABI目录中(这也是ndk-build命令默认生成.so文件的目录)在AAR压缩包中的路径AAR压缩包中位于jni/ABI目录中(.so文件会自动包含到引用AAR压缩包的APK中)在APK中的路径最终APK文件中的lib/ABI目录中通过PackageManager安装后,.so文件路径
上一篇: 下一篇:Android开发-瀑布流效果的实现 - Android当前位置:& &&&Android开发-瀑布流效果的实现Android开发-瀑布流效果的实现&&网友分享于:&&浏览:0次Android开发--瀑布流效果的实现&&&& 对手机App的瀑布流效果一直有所耳闻,却从未自己亲自动手实践,趁着这几天还有些时间,做了些研究,也参考了网络上很多大神的博客,终于写出来自己的瀑布流效果了,先上一图。
&&&&& 正如图所示:瀑布流的原理很简单,就是自己重新写一个ScrollView,添加一个横向排布的LinearLayout,再向这个横向的LinearLayout中添加三个纵向排布的LinearLayout,接着我们就可以向每个一LinearLayout中依次添加图片。原理很容易理解,但实践起来也很困难,需要注意的问题也很多:
&&&&& 1.为了防止OOM,我们应当对那些不可见的图片进行回收,在这里我的思路是:如果以一个屏幕的高度为一页的话,只在当前的程序中缓存下来三页数量的图片,即当前页,前一页和后一页,这样可以提高用户体验。为了回收图片,我们就需要重写一个View来显示瀑布流中的每一图片,异步的去加载Bitmap和回收Bitmap。
&&&&& 2.在ScrollView滑动的过程中监听图片可见性的变化,在这里用两个数组来记录三页中每一个LinearLayout的最上端和最低端的子View的id。
&&&&& 3.利用一个Lrucache来加快图片的响应时间。
下面是我的代码,如果各位大神发现错误,还请多多指教。
WaterFallView瀑布流显示整体布局类
package com.example.waterfalltest.
import java.util.ArrayL
import java.util.L
import android.content.C
import android.graphics.C
import android.util.AttributeS
import android.view.V
import android.widget.LinearL
import android.widget.ScrollV
import android.widget.T
import com.example.waterfalltest.widget.WaterFallItem.LoadCompletedL
* 需调用setup方法首先对WaterFallView进行配置初始化
* 根布局为一个横向的LinearLayout,然后根据设置的列数依次添加纵向的LinearLayout,每次将图片加进纵向LinearLayout中
* 如果以一个屏幕的高度为一页的话,只在当前的程序中缓存下来三页数量的图片
* @author acer
public class WaterFallView extends ScrollView {
private static final String TAG = &WaterFallView&;
private LinearLayout mContainerL
private ArrayList&LinearLayout& mLayoutsL
private final static int PAGE_COUNT = 20;
private int currentPage = 0;
private int colN
private int colW
private int colHeight[];
private List&String& mImageU
private int screenH
private int[] topIndexA//记录三页中顶部Item在LinearLayout的Id
private int[] bottomIndexA//记录三页中底部Item在LinearLayout的Id
private int[] lastBottomIndexA//所有Item中的最低部
public WaterFallView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
public WaterFallView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
public WaterFallView(Context context) {
super(context);
// TODO Auto-generated constructor stub
private void init() {
mContainerLayout = new LinearLayout(getContext());
mContainerLayout.setBackgroundColor(Color.WHITE);
mContainerLayout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT);
addView(mContainerLayout, layoutParams);
mLayoutsList = new ArrayList&LinearLayout&();
screenHeight = getResources().getDisplayMetrics().heightP
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (getScrollY() + getHeight() &= computeVerticalScrollRange()) {// 已经加载到底部
loadOnpage();
if (t & oldt) {// 向下滑动
for (int i = 0; i & colN i++) {
LinearLayout layout = mLayoutsList.get(i);
WaterFallItem topItem = (WaterFallItem) layout
.getChildAt(topIndexArray[i]);
if (topItem.getPositionY() & getScrollY() - screenHeight) {
topItem.recycle();
topIndexArray[i]++;
WaterFallItem bomItem = (WaterFallItem) layout
.getChildAt(Math.min(bottomIndexArray[i] - 1, lastBottomIndexArray[i]));
if (bomItem.getPositionY() &= getScrollY() + 2 * screenHeight) {
bomItem.reloadBitmap();
bottomIndexArray[i] = Math.min(
bottomIndexArray[i] + 1, lastBottomIndexArray[i]);
} else {// 向上滑动
for (int i = 0; i & colN i++) {
LinearLayout layout = mLayoutsList.get(i);
WaterFallItem bomItem = (WaterFallItem) layout
.getChildAt(bottomIndexArray[i] - 1);
if (bomItem.getPositionY() & getScrollY() + 2 * screenHeight) {
bomItem.recycle();
bottomIndexArray[i]--;
WaterFallItem topItem = (WaterFallItem) layout
.getChildAt(Math.max(topIndexArray[i] - 1, 0));
if (topItem.getPositionY() &= getScrollY() - screenHeight) {
topItem.reloadBitmap();
topIndexArray[i] = Math.max(
topIndexArray[i] - 1, 0);
public void setUp(List&String& imgUrl, int col) {
colWidth = getResources().getDisplayMetrics().widthPixels /
mImageUrl = imgU
colHeight = new int[col];
bottomIndexArray = new int[col];
topIndexArray = new int[col];
lastBottomIndexArray = new int[col];
for (int i = 0; i & i++) {
LinearLayout.LayoutParams colLayoutParams = new LinearLayout.LayoutParams(
colWidth, LinearLayout.LayoutParams.WRAP_CONTENT);
LinearLayout layout = new LinearLayout(getContext());
layout.setOrientation(LinearLayout.VERTICAL);
mContainerLayout.addView(layout, colLayoutParams);
mLayoutsList.add(layout);
loadOnpage();
private void loadOnpage() {
if (mImageUrl.size() & (currentPage + 1) * PAGE_COUNT) {
end = (currentPage + 1) * PAGE_COUNT;
end = mImageUrl.size();
for (int i = currentPage * PAGE_COUNT; i & i++) {
WaterFallItem item = new WaterFallItem(getContext(), colWidth - 10);
item.setId(i);
item.loadBitmap(&images/& + mImageUrl.get(i));
item.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
// TODO Auto-generated method stub
WaterFallItem item = (WaterFallItem) arg0;
Toast.makeText(getContext(), &click:& + item.getId(),
Toast.LENGTH_SHORT).show();
final int layoutId = i % colN
item.setLoadCompletedListener(new LoadCompletedListener() {
public void completed(WaterFallItem waterFallItem, int height) {
// TODO Auto-generated method stub
LinearLayout layout = mLayoutsList.get(layoutId);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.setMargins(5, 10, 5, 0);
layout.addView(waterFallItem, layoutParams);
colHeight[layoutId] += (height + 10);
waterFallItem.setPositionY(colHeight[layoutId]);
lastBottomIndexArray[layoutId]++;
if (currentPage == 1
&& waterFallItem.getPositionY() & 2 * screenHeight) {
bottomIndexArray[layoutId]++;
currentPage++;
WaterFallItem类,用来回收和加载图片,即图中的Item
package com.example.waterfalltest.
import android.content.C
import android.graphics.B
import android.graphics.C
import android.graphics.C
import android.graphics.P
import android.graphics.R
import android.os.AsyncT
import android.view.V
* 瀑布流中的Item自定义View
* 负责Bitmap的加载以及回收工作,并记录下所需的数据
* @author acer
public class WaterFallItem extends View {
private static final String TAG = &WaterFallItem&;
//View的高度
//View的宽度
private int positionY;//View中底部距离整个ScrollView最顶部的距离
private Paint mP
private Rect dstR
private boolean isFirstLoad =
private String mUrlS
private Bitmap mB
private LoadCompletedListener loadCompletedL
public WaterFallItem(Context context, int width) {
super(context);
// TODO Auto-generated constructor stub
this.width =
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.WHITE);
public void loadBitmap(String url){
this.mUrlString =
new LoadBitmapTask().execute(url);
public void reloadBitmap(){
isFirstLoad =
loadBitmap(mUrlString);
* 防止OOM进行回收
public void recycle() {
if (mBitmap == null || mBitmap.isRecycled())
new Thread(new Runnable() {
public void run() {
if (mBitmap != null) {
mBitmap.recycle();
GetBitmapUtils.removeBitmap(mUrlString);
}).start();
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
if (mBitmap != null) {
canvas.drawBitmap(mBitmap, null, dstRect, mPaint);
else if(dstRect != null) {
canvas.drawRect(dstRect, mPaint);
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(width, height);
public int getId() {
public void setId(int id) {
public int getmHeight(){
public void setLoadCompletedListener(LoadCompletedListener loadCompletedListener) {
this.loadCompletedListener = loadCompletedL
public int getPositionY() {
return positionY;
public void setPositionY(int positionY) {
this.positionY = positionY;
private class LoadBitmapTask extends AsyncTask&String, Void, Void&{
protected Void doInBackground(String... arg0) {
// TODO Auto-generated method stub
String url = arg0[0];
mBitmap = GetBitmapUtils.getBitmap(getContext(), url);
if (mBitmap != null) {
int bmpWidth = mBitmap.getWidth();
int bmpHeight = mBitmap.getHeight();
height = (int) (bmpHeight * width / bmpWidth);
dstRect = new Rect(0, 0, width, height);
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if (mBitmap != null) {
WaterFallItem.this.invalidate();
if (isFirstLoad && loadCompletedListener != null) {
pleted(WaterFallItem.this, height);
public interface LoadCompletedListener {
public void completed(WaterFallItem waterFallItem, int height);
GetBitmapUtils,加载Bitmap工具类
package com.example.waterfalltest.
import java.io.IOE
import java.io.InputS
import android.content.C
import android.graphics.B
import android.graphics.BitmapF
import android.util.LruC
* 加载Bitmap的工具类
* @author acer
public class GetBitmapUtils {
private static LruCache&String, Bitmap& mLruCache = new LruCache&String, Bitmap&(
public static Bitmap getBitmap(Context context, String url) {
Bitmap bitmap = mLruCache.get(url);
if (bitmap == null) {//可以在这里换成网络加载
InputStream inStream =
inStream = context.getAssets().open(url);
bitmap = BitmapFactory.decodeStream(inStream);
inStream.close();
inStream =
} catch (IOException e) {
e.printStackTrace();
if (bitmap != null) {
mLruCache.put(url, bitmap);
public static void removeBitmap(String url) {
mLruCache.remove(url);
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 1234567891011 Copyright & &&版权所有}

我要回帖

更多关于 android 自定义瀑布流 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信