`
isiqi
  • 浏览: 16491424 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

Android 自定义控件-SnakeLayout (仿gallery)

阅读更多

转载请注明转载地址:

http://wallage.blog.163.com/blog/static/1738962420108211120850/

简要介绍:相信大部分用过android Gallery控件的人,对gallery这个控件可谓是又爱又恨,gallery动画效果不错,非常实用,可是却有很多限制,从布局上来讲,gallery仅能水平放置,若想使用垂直放置的gallery,除非重写gallery。本文所述SnakeLayout继承于FrameLayout,用户可在SnakeLayout里自定义多个ImageView (大于等于3)的位置,并将指定的ID分配给所定义的ImageView;之后在主文件里进行简单的初始化后,就可以像gallery一样拖动所定义的ImageView,如同一条蛇一样连续的移动,不仅能横着拖,竖着拖,还能斜着拖,甚至绕圈圈。

效果图如下(android虚拟机长宽为800*600):

Android 自定义控件-SnakeLayout (仿gallery) - Wallace - 懒羊羊的南瓜屋
Android 自定义控件-SnakeLayout (仿gallery) - Wallace - 懒羊羊的南瓜屋
(测试版)代码如下:
package com.Snake;
/*
* Author: Wallace Wang
* Email: wallage@qq.com
*/
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnGestureListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
public class SnakeLayout extends FrameLayout {
private static final String LOG_TAG = "SnakeLayout";
private GestureDetector mGestureDetector;
private SnakeOnGestureListener mGestureListener;
private List<View> ViewHolder;
private int selectImg;
private int totalViewNum;
private View mContentView;
private SnakeView ScrollView;
private Context mContext;
private enum State {
ABOUT_TO_ANIMATE,
ANIMATING,
ANIMATE_END,
READY,
TRACKING
};
private State mState;
private double aniStartPos;// Value = scrollNum + percent*direction;
private double aniStopPos;// Value = scrollNum + percent*direction;
private Date aniStartTime;
private long aniTime = 1000;
private double aniSpeed = 500;
private double aniDefG = 5;

private int mContentWidth = 0;
private int mContentHeight = 0;
private int clickItem = -1;
private int direction = 0;
private int movDirection = 0;
private double percent = 0;
private int scrollNum = 0;
private PathScale myPathViews;
private List<Bitmap> BmpRecViews;
private OnSelectListener selectListener;
private OnClickListener clickListener;
private int currentIndex = 0;
public SnakeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(LOG_TAG, "Init Snake Layout");
mContext = context;
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SnakeLayout);
selectImg = a.getInteger(R.styleable.SnakeLayout_selectImg, -1);
a.recycle();
mGestureListener = new SnakeOnGestureListener();
mGestureDetector = new GestureDetector(mGestureListener);
mGestureDetector.setIsLongpressEnabled(false);
BmpRecViews = new ArrayList<Bitmap>();
myPathViews = new PathScale();
mState = State.READY;
}
public void Init(){
for (int i = 0; i < totalViewNum; i++) {
ImageView v = (ImageView)ViewHolder.get(i);
v.setScaleType(ImageView.ScaleType.FIT_XY);
v.setImageBitmap(BmpRecViews.get((i + currentIndex)% BmpRecViews.size()));
}
}

public void addBitmap(Bitmap b){
if(b != null)
BmpRecViews.add(b);
}

public void addBitmap(Bitmap b, int position){
if(b != null)
BmpRecViews.add(position, b);
}

public void addRec(int rec){
Bitmap b = BitmapFactory.decodeResource(this.getResources(),rec);
if(b != null)
BmpRecViews.add(b);
}
......
代码太长,省略
res/values/attrs.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SnakeLayout">
<!-- Defines the special selected position Image -->
<attr name="selectImg" format="integer" />
</declare-styleable>
</resources>
res/values/ids.xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="snakeImg0" />
<item type="id" name="snakeImg1" />
<item type="id" name="snakeImg2" />
<item type="id" name="snakeImg3" />
<item type="id" name="snakeImg4" />
<item type="id" name="snakeImg5" />
<item type="id" name="snakeImg6" />
<item type="id" name="snakeImg7" />
<item type="id" name="snakeImg8" />
<item type="id" name="snakeImg9" />
<item type="id" name="snakeImg10" />
<item type="id" name="snakeImg11" />
<item type="id" name="snakeImg12" />
<item type="id" name="snakeImg13" />
<item type="id" name="snakeImg14" />
<item type="id" name="snakeImg15" />
<item type="id" name="snakeImg16" />
<item type="id" name="snakeImg17" />
<item type="id" name="snakeImg18" />
<item type="id" name="snakeImg19" />
<item type="id" name="snakeImg20" />
<item type="id" name="snakeImg21" />
<item type="id" name="snakeImg22" />
<item type="id" name="snakeImg23" />
<item type="id" name="snakeImg24" />
<item type="id" name="snakeImg25" />
<item type="id" name="snakeImg26" />
<item type="id" name="snakeImg27" />
<item type="id" name="snakeImg28" />
<item type="id" name="snakeImg29" />
<item type="id" name="snakeContent" />
</resources>
主布局文件:main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:snake="http://schemas.android.com/apk/res/com.Snake"
android:orientation="vertical" android:background="@drawable/bj"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.Snake.SnakeLayout android:layout_width="fill_parent" android:layout_weight="1"
android:id="@+id/my_snake" android:layout_height="fill_parent"
snake:selectImg="7">
<LinearLayout android:layout_width="fill_parent" android:orientation="vertical"
android:layout_height="wrap_content" android:id="@id/snakeContent">
<LinearLayout android:layout_width="fill_parent" android:paddingTop="70dip"
android:layout_height="wrap_content">
<TextView android:layout_width="270dip" android:layout_height="1dip"/>
<ImageView android:layout_width="40dip" android:id="@id/snakeImg0"
android:layout_height="40dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="300dip" android:layout_height="1dip"/>
<ImageView android:layout_width="60dip" android:id="@id/snakeImg1"
android:layout_height="60dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="295dip" android:layout_height="1dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg2"
android:layout_height="50dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="290dip" android:layout_height="1dip"/>
<ImageView android:layout_width="35dip" android:id="@id/snakeImg3"
android:layout_height="35dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="290dip" android:layout_height="1dip"/>
<ImageView android:layout_width="35dip" android:id="@id/snakeImg4"
android:layout_height="35dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="292dip" android:layout_height="1dip"/>
<ImageView android:layout_width="40dip" android:id="@id/snakeImg5"
android:layout_height="40dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="320dip" android:layout_height="1dip"/>
<ImageView android:layout_width="40dip" android:id="@id/snakeImg6"
android:layout_height="40dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg7"
android:layout_height="55dip" android:paddingTop="15dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg8"
android:layout_height="55dip" android:paddingTop="15dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg9"
android:layout_height="55dip" android:paddingTop="15dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg10"
android:layout_height="50dip" android:paddingTop="10dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg11"
android:layout_height="40dip" android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg12"
android:layout_height="40dip" android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg13"
android:layout_height="50dip" android:paddingLeft="10dip"
android:paddingTop="10dip"/>
</LinearLayout>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="260dip" android:layout_height="1dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg21"
android:layout_height="25dip"
android:paddingLeft="25dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg20"
android:layout_height="55dip" android:paddingTop="20dip"
android:paddingLeft="15dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg19"
android:layout_height="65dip" android:paddingTop="25dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg18"
android:layout_height="65dip" android:paddingTop="25dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg17"
android:layout_height="55dip" android:paddingTop="15dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="50dip" android:id="@id/snakeImg16"
android:layout_height="45dip" android:paddingTop="5dip"
android:paddingLeft="10dip"/>
<ImageView android:layout_width="45dip" android:id="@id/snakeImg15"
android:layout_height="35dip" android:paddingLeft="10dip"/>
<ImageView android:layout_width="45dip" android:id="@id/snakeImg14"
android:layout_height="35dip" android:paddingLeft="10dip"/>
</LinearLayout>
</LinearLayout>
</com.Snake.SnakeLayout>
</LinearLayout>
Snake.java 文件:
package com.Snake;
import android.app.Activity;
import android.os.Bundle;
public class Snake extends Activity {
/** Called when the activity is first created. */
SnakeLayout mSnake;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mSnake = (SnakeLayout)findViewById(R.id.my_snake);
mSnake.addRec(R.drawable.png1);
mSnake.addRec(R.drawable.png2);
mSnake.addRec(R.drawable.png3);
mSnake.addRec(R.drawable.png4);
mSnake.addRec(R.drawable.png5);
mSnake.addRec(R.drawable.png6);
mSnake.addRec(R.drawable.png7);
mSnake.addRec(R.drawable.png8);
mSnake.addRec(R.drawable.png9);
mSnake.addRec(R.drawable.png10);
mSnake.addRec(R.drawable.png11);
mSnake.addRec(R.drawable.png12);
mSnake.addRec(R.drawable.png13);
mSnake.addRec(R.drawable.png14);
mSnake.addRec(R.drawable.png15);
mSnake.addRec(R.drawable.png16);
mSnake.addRec(R.drawable.png17);
mSnake.addRec(R.drawable.png18);
mSnake.addRec(R.drawable.png19);
mSnake.addRec(R.drawable.png20);
mSnake.addRec(R.drawable.png21);
mSnake.addRec(R.drawable.png22);
mSnake.addRec(R.drawable.png23);
mSnake.addRec(R.drawable.png24);
mSnake.addRec(R.drawable.png25);
mSnake.addRec(R.drawable.png26);
mSnake.addRec(R.drawable.png27);
mSnake.addRec(R.drawable.png28);
mSnake.Init();
}
}
分享到:
评论

相关推荐

    自定义组件:SnakeLayout

    【标题】:“自定义组件:SnakeLayout” 在Android开发中,自定义组件是...通过深入学习SnakeLayout,开发者不仅可以掌握一个实用的工具,还能提升自身在Android自定义组件开发上的能力,为未来的项目积累宝贵经验。

    用SnakeLayout实现纵向Gallery完整代码

    SnakeLayout是一种自定义布局,它在Android开发中用于创建各种动态翻页效果,如这里的纵向Gallery。这个完整的代码示例提供了如何使用SnakeLayout来实现一个可以从上至下或从下至上的翻页效果,类似于画廊中的图片...

    FlexLayouts 布局

    Flex 自定义布局 FlowLayout SnakeLayout CircleLayout RectangleLayout 官方下载地址:http://flexlayouts.org/download/

    自定义布局 FlexLayouts 源码

    FlexLayouts 自定义布局源码 src\org\flexlayouts\layouts\CircleLayout.as src\org\flexlayouts\layouts\FlowLayout.as src\org\flexlayouts\layouts\RectangleLayout.as src\org\flexlayouts\layouts\SnakeLayout....

    基于springboot的文物管理系统源码数据库文档.zip

    基于springboot的文物管理系统源码数据库文档.zip

    springboot329数计学院学生综合素质评价系统的设计与开发.zip

    论文描述:该论文研究了某一特定领域的问题,并提出了新的解决方案。论文首先对问题进行了详细的分析和理解,并对已有的研究成果进行了综述。然后,论文提出了一种全新的解决方案,包括算法、模型或方法。在整个研究过程中,论文使用了合适的实验设计和数据集,并进行了充分的实验验证。最后,论文对解决方案的性能进行了全面的评估和分析,并提出了进一步的研究方向。 源码内容描述:该源码实现了论文中提出的新的解决方案。源码中包含了算法、模型或方法的具体实现代码,以及相关的数据预处理、实验设计和性能评估代码。源码中还包括了合适的注释和文档,以方便其他研究者理解和使用。源码的实现应该具有可读性、可维护性和高效性,并能够复现论文中的实验结果。此外,源码还应该尽可能具有通用性,以便在其他类似问题上进行进一步的应用和扩展。

    基于SpringBoot+Vue的美容店信息管理系统源码数据库文档.zip

    基于SpringBoot+Vue的美容店信息管理系统源码数据库文档.zip

    IMG_9750.PNG

    IMG_9750.PNG

    javaweb项目 - 学生管理系统

    javaweb项目 - 学生管理系统

    前端铺子开发者 前端杂货铺 小程序在线课堂+工具组件小程序uniapp移动端.zip

    前端铺子开发者 前端杂货铺 小程序在线课堂+工具组件小程序uniapp移动端.zip

    毕业设计《SSM-HTML5酒店预订宾馆客房入住管理系统(可升级SpringBoot)》+Java项目源码+文档说明

    <项目介绍> - 前台技术框架: Bootstrap(一个HTML5响应式框架) 程序开发环境:myEclipse/Eclipse/Idea都可以 + mysql数据库 后台架构框架: SSM(SpringMVC + Spring + Mybatis) - 不懂运行,下载完可以私聊问,可远程教学 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------

    (源码)基于PaddleDetection框架的人流量统计系统.zip

    # 基于PaddleDetection框架的人流量统计系统 ## 项目简介 本项目是一个基于PaddleDetection框架的人流量统计系统,专注于静态和动态场景下的人员计数和行人检测。项目涵盖了从数据准备、模型选择、训练、评估、优化到预测和部署的完整流程,旨在提供高效、准确的人流量统计解决方案。 ## 主要特性和功能 多模型支持支持多种模型选择,如DeepSORT、JDE和FairMOT,适用于多目标追踪场景。 模型优化提供多种优化策略,包括数据增强、可变形卷积、syncbn+ema、attention和GIoU Loss,以提升模型精度。 性能加速支持TensorRT推理加速,显著提升模型性能。 数据增强提供多种数据增强方式,如cutmix、syncbn和ema,进一步优化模型性能。 模型导出支持模型导出,便于模型部署和上线。 ## 安装使用步骤 1. 安装PaddleDetection框架 bash

    Cocos2d-x教程视频Cocos2d-x游戏实战项目开发记忆卡片

    Cocos2d-x教程视频Cocos2d-x游戏实战项目开发记忆卡片提取方式是百度网盘分享地址

    基于RNN生成文本(自然语言处理)

    此代码基于PTB数据集,实现了一个具有一定泛化能力的语言模型。可指定初始单词和生成单词数生成文本

    (源码)基于MQTT协议和Docker的IoT远程监控管理系统.zip

    # 基于MQTT协议和Docker的IoT远程监控管理系统 ## 项目简介 此项目旨在通过MQTT协议实现IoT设备的远程监控与管理,结合Docker技术实现服务器端的轻量化部署。通过Esp32微控制器连接IoT设备和MQTT服务器,实现数据的采集、传输和展示。 ## 项目的主要特性和功能 1. 自动化配置实现Esp32微控制器的自动化配置,通过WiFi连接MQTT服务器。 2. 图形化界面提供图形化界面,方便用户配置WiFi和MQTT服务器的连接凭证。 3. 远程固件更新支持远程固件更新,确保设备始终运行在最新状态。 4. Docker部署利用Docker技术,实现服务器端轻量化部署,方便管理和维护。 5. 实时数据传输通过MQTT协议实现数据的实时传输和展示,适用于多种IoT设备。 ## 安装使用步骤 1. 下载源码下载并解压项目源码文件。 2. 配置Docker环境根据项目需求,配置Docker环境,并启动相应的Docker容器。

    (源码)基于Qt框架的智能家居管理系统.zip

    # 基于Qt框架的智能家居管理系统 ## 项目简介 本项目是一个基于Qt框架开发的智能家居管理系统,旨在提供一个集成的平台来监控和管理家庭环境中的各种传感器数据,如温度、湿度、烟雾状态、红外状态等。系统通过图形界面实时展示数据,并提供警报功能以应对异常情况。 ## 项目的主要特性和功能 1. 实时数据监控通过Qt和Qwt库创建的曲线图,实时显示温度和湿度数据。 2. 多传感器支持支持温度、湿度、烟雾、红外等多种传感器的监控。 3. 警报系统当传感器数据超过设定阈值时,系统会触发警报,并通过界面显示警告信息。 4. 用户交互提供滑动条和复选框,允许用户调整警报阈值或关闭警报。 5. 网络通信通过TCP套接字与服务器通信,获取和发送传感器数据及网络拓扑信息。 6. 蓝牙数据读取支持通过蓝牙读取传感器数据并更新界面显示。 ## 安装使用步骤 1. 环境准备 确保已安装Qt开发环境。 安装Qwt库以支持曲线图功能。

    SpringBoot 整合 Druid 课件

    建立数据库连接池对象(服务器启动)。 按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。 对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。 存取数据库。 关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。 释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。

    (源码)基于物联网技术的远程医疗机器人系统.zip

    # 基于物联网技术的远程医疗机器人系统 ## 项目简介 本项目通过结合物联网技术和移动设备,实现了一个远程医疗机器人系统。通过远程控制和监测,医生可以在不同地点和环境中进行操作和观察,从而提高医疗服务效率和便利性。本系统的应用场景包括医院、手术室和病房等场景,旨在解决医生无法实时出现在患者身边的问题。 ## 项目的主要特性和功能 本项目的主要特性和功能包括 1. 远程控制医生可以通过BLYNK应用程序控制医疗机器人,实现在远程环境中的导航和操作。 2. 实时监控医疗机器人配备有摄像头和传感器,医生可以实时观察患者情况和手术室环境。 3. 温度监测医疗机器人内置温度传感器,可以测量患者的体温,无需直接接触患者。 4. 药品管理医疗机器人配备有药品箱,可以方便地进行药品的存储和管理。 ## 安装使用步骤 假设用户已经下载了本项目的源码文件,以下是安装使用步骤

    (源码)基于JavaFX的图片管理系统.zip

    # 基于JavaFX的图片管理系统 ## 项目简介 本项目是一个基于JavaFX的图片管理系统,旨在提供一个用户友好的界面来管理和浏览图片。系统支持图片的预览、重命名、删除、复制、粘贴等操作,并提供了多种排序和展示方式。 ## 项目的主要特性和功能 1. 预览窗口 目录树展示 缩略图预览 单选、多选(Ctrl+左键)、框选功能 图片信息显示(如文件名、大小、最后修改时间等) 2. 右键菜单 复制粘贴图片 单选和多选重命名 删除图片 3. 展示窗口 图片放大缩小 左右切换图片 幻灯片播放功能 4. 排序功能 按文件名排序 按文件大小排序 按最后修改时间排序 5. 其他功能 图片信息封装(ImageBean) 文件树节点管理(FileTreeItem)

    (源码)基于TensorFlow的中文文本分类系统.zip

    # 基于TensorFlow的中文文本分类系统 ## 项目简介 本项目是一个基于TensorFlow的中文文本分类系统,使用卷积神经网络(CNN)和循环神经网络(RNN)进行文本分类。项目涵盖了从数据预处理、模型训练、模型评估到模型预测的全流程,旨在提供一个高效的中文文本分类解决方案。 ## 主要特性和功能 数据预处理包括读取文件数据、构建词汇表、转换分类目录、将文本数据转换为ID序列表示等。 模型构建实现了基于CNN和RNN的文本分类模型,支持LSTM和GRU作为RNN的单元。 模型训练提供了详细的训练配置,包括学习率、批次大小、迭代轮次等参数的设置。 模型评估在验证集上评估模型的性能,输出准确率、损失等信息,并生成混淆矩阵。 模型预测加载训练好的模型,对新的文本消息进行分类预测,并输出预测类别。 ## 安装使用步骤 1. 环境准备 安装Python 23 安装TensorFlow 1.3以上

Global site tag (gtag.js) - Google Analytics