私の理解では、ビューが小さすぎて簡単に触れることができない場合は、TouchDelegateを使用して、そのビューのクリック可能な領域を増やすことになっています。
ただし、Googleで使用例を検索すると、複数の人が質問をしますが、回答はほとんどありません。
ビューのタッチデリゲートを設定して、クリック可能な領域をすべての方向に4ピクセル増やすなど、適切な方法を知っている人はいますか?
私の理解では、ビューが小さすぎて簡単に触れることができない場合は、TouchDelegateを使用して、そのビューのクリック可能な領域を増やすことになっています。
ただし、Googleで使用例を検索すると、複数の人が質問をしますが、回答はほとんどありません。
ビューのタッチデリゲートを設定して、クリック可能な領域をすべての方向に4ピクセル増やすなど、適切な方法を知っている人はいますか?
回答:
Googleの友人に聞いたところ、TouchDelegateの使い方を理解するのを手伝ってくれました。これが私たちが思いついたものです:
final View parent = (View) delegate.getParent();
parent.post( new Runnable() {
// Post in the parent's message queue to make sure the parent
// lays out its children before we call getHitRect()
public void run() {
final Rect r = new Rect();
delegate.getHitRect(r);
r.top -= 4;
r.bottom += 4;
parent.setTouchDelegate( new TouchDelegate( r , delegate));
}
});
これは、主にこのブログ投稿から描画した1つの画面に複数のビュー(チェックボックス)を表示することで実現できました。基本的に、emmbyのソリューションを使用して、各ボタンとその親に個別に適用します。
public static void expandTouchArea(final View bigView, final View smallView, final int extraPadding) {
bigView.post(new Runnable() {
@Override
public void run() {
Rect rect = new Rect();
smallView.getHitRect(rect);
rect.top -= extraPadding;
rect.left -= extraPadding;
rect.right += extraPadding;
rect.bottom += extraPadding;
bigView.setTouchDelegate(new TouchDelegate(rect, smallView));
}
});
}
私の場合、チェックボックスが上にオーバーレイされたimageviewsのグリッドビューがあり、次のようにメソッドを呼び出しました。
CheckBox mCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox1);
final ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView1);
// Increase checkbox clickable area
expandTouchArea(imageView, mCheckBox, 100);
私にとって素晴らしい仕事をしています。
このソリューションは、@ BrendanWeinsteinによってコメントで投稿されました。
を送信する代わりに、のメソッドをTouchDelegateオーバーライドできます(拡張する場合)。getHitRect(Rect)View
public class MyView extends View { //NOTE: any other View can be used here
/* a lot of required methods */
@Override
public void getHitRect(Rect r) {
super.getHitRect(r); //get hit Rect of current View
if(r == null) {
return;
}
/* Manipulate with rect as you wish */
r.top -= 10;
}
}
emmbyのアプローチは私にはうまくいきませんでしたが、少し変更した後、うまくいきました。
private void initApplyButtonOnClick() {
mApplyButton.setOnClickListener(onApplyClickListener);
final View parent = (View)mApplyButton.getParent();
parent.post(new Runnable() {
@Override
public void run() {
final Rect hitRect = new Rect();
parent.getHitRect(hitRect);
hitRect.right = hitRect.right - hitRect.left;
hitRect.bottom = hitRect.bottom - hitRect.top;
hitRect.top = 0;
hitRect.left = 0;
parent.setTouchDelegate(new TouchDelegate(hitRect , mApplyButton));
}
});
}
多分それは誰かの時間を節約することができます
@Mason Leeのコメントによると、これで私の問題は解決しました。私のプロジェクトには、相対的なレイアウトと1つのボタンがありました。つまり、親は->レイアウトであり、子は->ボタンです。
これがグーグルリンクの例グーグルコードです
彼の非常に貴重な答えを削除する場合、私は彼の答えをここに置きました。
最近、TouchDelegateの使用方法について尋ねられました。私はこれについて少し錆びていて、それに関する良いドキュメントを見つけることができませんでした。これが私が少し試行錯誤した後に書いたコードです。touch_delegate_viewは、IDがtouch_delegate_rootの単純なRelativeLayoutです。レイアウトの単一の子であるボタンdelegated_buttonを使用して定義しました。この例では、ボタンのクリック可能な領域をボタンの上部から200ピクセル上に拡張します。
public class TouchDelegateSample extends Activity { Button mButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.touch_delegate_view); mButton = (Button)findViewById(R.id.delegated_button); View parent = findViewById(R.id.touch_delegate_root); // post a runnable to the parent view's message queue so its run after // the view is drawn parent.post(new Runnable() { @Override public void run() { Rect delegateArea = new Rect(); Button delegate = TouchDelegateSample.this.mButton; delegate.getHitRect(delegateArea); delegateArea.top -= 200; TouchDelegate expandedArea = new TouchDelegate(delegateArea, delegate); // give the delegate to an ancestor of the view we're delegating the // area to if (View.class.isInstance(delegate.getParent())) { ((View)delegate.getParent()).setTouchDelegate(expandedArea); } } }); } }乾杯、ジャスティンAndroidチーム@ Google
私からのいくつかの言葉:左側を拡張したい場合はマイナスで値を与え、オブジェクトの右側を拡張したい場合はプラスで値を与えます。これは、上部と下部で同じように機能します。
その特定のコンポーネント(ボタン)にパディングを与えるのは良い考えではありませんか。
パーティーに少し遅れましたが、多くの調査の後、私は現在使用しています:
/**
* Expand the given child View's touchable area by the given padding, by
* setting a TouchDelegate on the given ancestor View whenever its layout
* changes.
*/*emphasized text*
public static void expandTouchArea(final View ancestorView,
final View childView, final Rect padding) {
ancestorView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
TouchDelegate delegate = null;
if (childView.isShown()) {
// Get hitRect in parent's coordinates
Rect hitRect = new Rect();
childView.getHitRect(hitRect);
// Translate to ancestor's coordinates
int ancestorLoc[] = new int[2];
ancestorView.getLocationInWindow(ancestorLoc);
int parentLoc[] = new int[2];
((View)childView.getParent()).getLocationInWindow(
parentLoc);
int xOffset = parentLoc[0] - ancestorLoc[0];
hitRect.left += xOffset;
hitRect.right += xOffset;
int yOffset = parentLoc[1] - ancestorLoc[1];
hitRect.top += yOffset;
hitRect.bottom += yOffset;
// Add padding
hitRect.top -= padding.top;
hitRect.bottom += padding.bottom;
hitRect.left -= padding.left;
hitRect.right += padding.right;
delegate = new TouchDelegate(hitRect, childView);
}
ancestorView.setTouchDelegate(delegate);
}
});
}
これは、親ビューだけでなく、任意の祖先ビューにTouchDelegateを設定できるため、受け入れられているソリューションよりも優れています。
受け入れられているソリューションとは異なり、祖先ビューのレイアウトが変更されるたびにTouchDelegateも更新されます。
プログラムでそれを行いたくない場合は、ボタン(ビュー)の背景として画像を使用している場合は、画像の周囲に透明な領域を作成するだけです。
灰色の領域を透明にして、タッチ領域を増やすことができます。

ほとんどの場合、より大きなタッチ領域を必要とするビューを別のヘッドレスビュー(人工透明ビュー)でラップし、ラッパービューにパディング/マージンを追加し、元のビューの代わりにラッパービューにもクリック/タッチをアタッチできます。より大きなタッチエリアが必要です。
タッチエリアを一般的に拡張するには、ほとんど制限がありません。次のコードを使用します。
これにより、指定さviewれたancestorビュー内の指定されたタッチ領域を指定さexpansionれたピクセル単位で拡張できます。指定されたビューが祖先レイアウトツリーにある限り、任意の祖先を選択できます。
public static void expandTouchArea(final View view, final ViewGroup ancestor, final int expansion) {
ancestor.post(new Runnable() {
public void run() {
Rect bounds = getRelativeBounds(view, ancestor);
Rect expandedBounds = expand(bounds, expansion);
// LOG.debug("Expanding touch area of {} within {} from {} by {}px to {}", view, ancestor, bounds, expansion, expandedBounds);
ancestor.setTouchDelegate(new TouchDelegate(expandedBounds, view));
}
private Rect getRelativeBounds(View view, ViewGroup ancestor) {
Point relativeLocation = getRelativeLocation(view, ancestor);
return new Rect(relativeLocation.x, relativeLocation.y,
relativeLocation.x + view.getWidth(),
relativeLocation.y + view.getHeight());
}
private Point getRelativeLocation(View view, ViewGroup ancestor) {
Point absoluteAncestorLocation = getAbsoluteLocation(ancestor);
Point absoluteViewLocation = getAbsoluteLocation(view);
return new Point(absoluteViewLocation.x - absoluteAncestorLocation.x,
absoluteViewLocation.y - absoluteAncestorLocation.y);
}
private Point getAbsoluteLocation(View view) {
int[] absoluteLocation = new int[2];
view.getLocationOnScreen(absoluteLocation);
return new Point(absoluteLocation[0], absoluteLocation[1]);
}
private Rect expand(Rect rect, int by) {
Rect expandedRect = new Rect(rect);
expandedRect.left -= by;
expandedRect.top -= by;
expandedRect.right += by;
expandedRect.bottom += by;
return expandedRect;
}
});
}
適用される制限:
TouchDelegateに設定できるのは1つだけViewGroupです。複数のタッチデリゲートを操作する場合は、別の祖先を選択するか、「複数のTouchDelegateの使用方法」で説明されているように構成するタッチデリゲートを使用します。TouchDelegateの長方形の新しいサイズを取得するためだけにレイアウトパスを待つというアイデアが気に入らなかったため、別の解決策を選びました。
public class TouchSizeIncreaser extends FrameLayout {
public TouchSizeIncreaser(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final View child = getChildAt(0);
if(child != null) {
child.onTouchEvent(event);
}
return true;
}
}
そして、レイアウトで:
<ch.tutti.ui.util.TouchSizeIncreaser
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp">
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</ch.tutti.ui.util.TouchSizeIncreaser>
アイデアは、TouchSizeIncreaser FrameLayoutがスピナー(任意の子ビューである可能性があります)をラップし、ヒット長方形でキャプチャされたすべてのタッチイベントを子ビューに転送するというものです。クリックに対して機能し、範囲外でクリックしてもスピナーが開きます。他のより複雑なケースにどのような影響があるかはわかりません。