我正在尝试创建一个支持对其内容进行平移和缩放的 ViewGroup。我在网上所能找到的只是在 ImageView 中执行此操作的想法和实现,而不是容器。我想显示一张 map ,并且在它上面我想显示多个标记,它们是 ImageButtons,因此用户可以点击它们来获取更多信息。这是在 iOS 上通过 UIScrollView 实现的,但我在 Android 上找不到替代方案。
我决定使用 FrameView,这样我就可以设置一个以图像为背景的 ImageView,并在其之上添加一个 RelativeLayout,我可以在其上添加 ImageButton 并使用边距定位它们。
我借用了 TouchImageView 的部分实现 here ,但我遇到了并发症。我从平移开始,我部分成功了,它平移了容器,但平移工作很糟糕,它抖动很多。这是我的代码:
public class ScrollingViewGroup extends FrameLayout {
private int x = 0;
private int y = 0;
// We can be in one of these 3 states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
// Remember some things for zooming
PointF last = new PointF();
PointF start = new PointF();
public ScrollingViewGroup(Context context) {
super(context);
sharedConstructing(context);
}
public ScrollingViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
sharedConstructing(context);
}
private void sharedConstructing(Context context) {
super.setClickable(true);
this.context = context;
mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mScaleDetector.onTouchEvent(event);
PointF curr = new PointF(event.getX(), event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
last.set(event.getX(), event.getY());
start.set(last);
mode = DRAG;
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
float deltaX = curr.x - last.x;
float deltaY = curr.y - last.y;
Log.d("ScrollingViewGroup", Float.toString(deltaX));
Log.d("ScrollingViewGroup", Float.toString(deltaY));
float scaleWidth = Math.round(origWidth * saveScale);
float scaleHeight = Math.round(origHeight * saveScale);
x += deltaX;
y += deltaY;
last.set(curr.x, curr.y);
}
break;
case MotionEvent.ACTION_UP:
mode = NONE;
int xDiff = (int) Math.abs(curr.x - start.x);
int yDiff = (int) Math.abs(curr.y - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
break;
}
// setImageMatrix(matrix);
setTranslationX(x);
setTranslationY(y);
invalidate();
return true; // indicate event was handled
}
});
}
非常感谢任何想法。
编辑:抖动似乎是原因,因为在移动时,deltaX 和 deltaY 在正数和负数之间交替,检查 LogCat ......仍然不确定为什么。 这是由 curr 变量引起的,它每次给出不同的值,但不是一致的,它们看起来好像手指会来回移动而不是仅仅向前移动。例如,curr.x 不是 0、1、2、3、4 等,而是 0、1、0.5、2、1.5 等。也不知道为什么。
最佳答案
我有一个满足某些先决条件的解决方案:
容器中的项目可以缩放和平移(但不能同时进行)。该代码还能够确定用户是否单击而不是移动或缩放。 ImageView 存储在 FrameLayout 中的 ArrayList 中,并一起缩放和移动。此代码的某些部分摘自 Ed Burnette ( Link ) 在 ZDNet 上的一篇非常好的文章,该文章摘自非常好的 Android 书籍“Hello, Android ”。
检查这段代码。您可以在任何 Activity 中使用此类作为布局。您甚至应该能够在 XML 中使用它。现在有一个在构造函数中调用的方法 initializeViews() ,您可以在其中对创建布局时应加载的 ImageView 进行硬编码。您应该在“ArrayList sampleBitmaps = new ArrayList();”行之后在此方法中添加一些位图。 对于实际使用,实现一个方法 addImageView(ImageView item) 可能会更好,您可以在其中动态添加 View 。
import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
public class TouchContainer extends FrameLayout implements OnTouchListener {
// constants
private static final Config DEFAULT_COLOR_DEPTH = Bitmap.Config.ARGB_4444;
private static final String TAG = "TouchContainer";
// fields
private ArrayList<ImageView> items;
public TouchContainer(Context ctx) {
this(ctx, null);
}
public TouchContainer(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
initializeViews(); // initialize some sample Bitmaps
}
/**
* This method is just to make an example
*/
protected void initializeViews() {
ScaleType scaleType = ScaleType.MATRIX;
// array needs to be created here if used in XML
items = new ArrayList<ImageView>();
ArrayList<Bitmap> sampleBitmaps = new ArrayList<Bitmap>();
// here you should add some bitmaps to the Array that will then be displayed in the container
// e.g. sampleBitmaps.add(blabla I'm a bitmap) :-)
ImageView iv = null;
boolean firstLoop = true;
for (Bitmap bitmap : sampleBitmaps) {
// Load the bitmaps into imageviews
iv = new ImageView(getContext());
iv.setImageBitmap(bitmap);
iv.setScaleType(scaleType);
if (firstLoop) {
// add the touch listener to the first image view that is stored in the ArrayList
iv.setOnTouchListener(this);
firstLoop = false;
}
// add view to the FrameLayout
this.addView(iv);
// add the imageview to the array
items.add(iv);
}
}
protected void transformImages(Matrix matrix) {
for (ImageView image : items) {
image.setImageMatrix(matrix);
}
}
Matrix matrix = new Matrix();
Matrix savedMatrix = new Matrix();
// states
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
static final int CLICK = 3;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
start.set(event.getX(), event.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
break;
case MotionEvent.ACTION_UP:
// figure out if user clicked
mode = NONE;
int xDiff = (int) Math.abs(event.getX() - start.x);
int yDiff = (int) Math.abs(event.getY() - start.y);
if (xDiff < CLICK && yDiff < CLICK)
performClick();
break;
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) {
matrix.set(savedMatrix);
matrix.postTranslate(event.getX() - start.x,
event.getY() - start.y);
}
else if (mode == ZOOM) {
float newDist = spacing(event);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f) {
matrix.set(savedMatrix);
float scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
}
break;
}
transformImages(matrix);
return true;
}
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
}
关于android - 构建可缩放/可平移的容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10416780/
在编写Ruby(客户端脚本)时,我看到了三种构建更长字符串的方法,包括行尾,所有这些对我来说“闻起来”有点难看。有没有更干净、更好的方法?变量递增。ifrender_quote?quote="NowthatthereistheTec-9,acrappyspraygunfromSouthMiami."quote+="ThisgunisadvertisedasthemostpopularguninAmericancrime.Doyoubelievethatshit?"quote+="Itactuallysaysthatinthelittlebookthatcomeswithit:themo
最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
关闭。这个问题需要更多focused.它目前不接受答案。想改进这个问题吗?更新问题,使其只关注一个问题editingthispost.关闭8年前。Improvethisquestion我们有以下(以及更多)系统,我们将数据从一个应用推送/拉取到另一个:托管CRM(InsideSales.com)Asterisk电话系统(内部)横幅广告系统(openx,我们托管)潜在客户生成系统(自行开发)电子商务商店(spree,我们托管)工作板(本土)一些工作网站抓取+入站工作提要电子邮件传送系统(如Mailchimp,自主开发)事件管理系统(如eventbrite,自主开发)仪表板系统(大量图表和
在我的mac上安装几个东西时遇到这个问题,我认为这个问题来自将我的豹子升级到雪豹。我认为这个问题也与macports有关。/usr/local/lib/libz.1.dylib,filewasbuiltfori386whichisnotthearchitecturebeinglinked(x86_64)有什么想法吗?更新更具体地说,这发生在安装nokogirigem时日志看起来像:xslt_stylesheet.c:127:warning:passingargument1of‘Nokogiri_wrap_xml_document’withdifferentwidthduetoproto
Ruby语言是否可以用于创建全新的移动操作系统或桌面操作系统,即是否可以用于系统编程? 最佳答案 嗯,现在有一些操作系统使用比C更高级的语言。基本上,ruby解释器本身需要用一些低级的东西来编写,并且需要一些引导加载代码将功能齐全的ruby解释器作为独立内核加载到内存中。一旦ruby解释器被引导并以内核模式(或innerrings之一)运行,就没有什么可以阻止您在其上构建整个操作系统。不幸的是,它可能会很慢。每个操作系统功能的垃圾收集可能会相当引人注目。ruby解释器将负责任务调度和网络堆栈等基本事情,使用垃圾收集框架会大大
这个问题在这里已经有了答案:Unabletoinstallgem-Failedtobuildgemnativeextension-cannotloadsuchfile--mkmf(LoadError)(17个答案)关闭9年前。嘿,我正在尝试在一台新的ubuntu机器上安装rails。我安装了ruby和rvm,但出现“无法构建gemnative扩展”错误。这是什么意思?$sudogeminstallrails-v3.2.9(没有sudo表示我没有权限)然后它会输出很多“获取”命令,最终会出现这个错误:Buildingnativeextensions.Thiscouldtakeawhi
我尝试了一些关于rubyonrails中openid利用率的搜索。然而,尽管出现了一组选项,例如omniauth、authlogic等,但这些gem通常用于构建接受openid身份验证的站点。换句话说,它们用于openid消费者设置。我也想构建自己的openid服务器。AssuggestedhereinOpenIdsite我发现了像Masquerade和local-openid这样的东西,不幸的是,它们不是非常活跃的项目,下载量很少。自建openidprovider服务器有没有其他设施可以推荐?非常感谢!!干杯,叶 最佳答案 虽
我正在尝试构建一个纯粹使用Ruby的聊天应用程序。有一个similarquestion较早发布,但我有不同的相关查询。我看过thisexample(与之前发布类似问题的人所提到的相同)。示例中的代码似乎对我不起作用。在终端上运行ruby脚本,并连接到url:http://localhost:1234在我的浏览器中,我无限期地遇到“正在从本地主机传输数据...”消息。此处的1234是所提供示例中使用的端口号。我无法弄清楚我运行失败的原因是什么。可能是我需要在执行脚本时在命令行中指定一些东西,或者我应该通过其他地方(可能是浏览器)开始聊天(输入输出)。我无法弄清楚到底该做什么。你能帮我
我想使用googlecharts创建一个如下所示的图表:GoogleChart.pie_400x200('TacoBell'=>0,'Mediterranean'=>2,'Shivas'=>5)给定一个对象Results(name,count)。如何为GoogleCharts的结构创建一个对象,如上所示?谢谢 最佳答案 从您在评论中列为@results的结果对象开始,以下应该有效:GoogleChart.pie_400x200(@results.map{|r|{r[:title]=>r[:percentage]}})