You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android自定义网格视图触摸坐标传递与WiFi扫描关联问题

嘿,这个问题我之前做类似的Android项目时也碰到过,其实有几种很实用的方式能把Custom View里选中的网格瓦片坐标传递到主Activity,进而触发关联的WiFi扫描。我给你拆解下最常用的两个方案:

方案1:接口回调(最经典直接的方式)

这个方法就像是给你的Custom View装了个“专属通知器”,一旦用户选中瓦片,它就会立刻把坐标信息告诉主Activity,逻辑清晰又好维护。

步骤拆解:

  1. 在Custom View里定义回调接口:先定好一个“约定”,告诉Activity我会传什么数据过去
  2. 给Custom View加监听器实例和设置方法:让Activity能“订阅”这个通知
  3. 在onTouchEvent里触发回调:拿到选中的(x,y)后,通知Activity
  4. 在主Activity里实现接口并处理逻辑:收到坐标后就启动WiFi扫描

Custom View代码示例:

public class GridDrawView extends View {
    // 定义回调接口,约定传递选中瓦片的x和y坐标
    public interface OnGridTileSelectedListener {
        void onTileSelected(int x, int y);
    }

    private OnGridTileSelectedListener mTileListener;

    // 给Activity提供设置监听器的方法
    public void setOnGridTileSelectedListener(OnGridTileSelectedListener listener) {
        mTileListener = listener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            // 这里用你已经实现的逻辑获取选中的瓦片x、y
            int selectedX = calculateTileX(event.getX());
            int selectedY = calculateTileY(event.getY());

            // 如果监听器已经设置,就触发回调把坐标传出去
            if (mTileListener != null) {
                mTileListener.onTileSelected(selectedX, selectedY);
            }
        }
        return super.onTouchEvent(event);
    }

    // 替换成你自己的坐标计算逻辑
    private int calculateTileX(float touchX) {
        // 比如根据网格宽度计算x索引
        return (int) (touchX / getTileWidth());
    }

    private int calculateTileY(float touchY) {
        // 比如根据网格高度计算y索引
        return (int) (touchY / getTileHeight());
    }

    // 你的其他绘制、网格初始化方法...
}

主Activity代码示例:

public class MainActivity extends AppCompatActivity implements GridDrawView.OnGridTileSelectedListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 找到布局里的Custom View,设置监听器
        GridDrawView gridView = findViewById(R.id.grid_draw_view);
        gridView.setOnGridTileSelectedListener(this);
    }

    // 实现接口里的方法,接收Custom View传过来的坐标
    @Override
    public void onTileSelected(int x, int y) {
        // 这里就是启动WiFi扫描的地方啦,直接把x、y关联进去
        startWifiScanWithTile(x, y);
    }

    private void startWifiScanWithTile(int tileX, int tileY) {
        // 替换成你自己的WiFi扫描逻辑,比如调用WiFiManager的scan方法
        Log.d("WiFi_Scan", "开始扫描,关联瓦片坐标: (" + tileX + ", " + tileY + ")");
        // 示例:获取WiFiManager并启动扫描
        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        if (wifiManager.isWifiEnabled()) {
            wifiManager.startScan();
            // 后续可以处理扫描结果,同时关联当前的tileX、tileY
        }
    }
}
方案2:使用ViewModel(适合MVVM架构/配置变化场景)

如果你的项目用了MVVM架构,或者需要在屏幕旋转等配置变化时保留选中的瓦片信息,那ViewModel是个更好的选择——它能在Activity重建时依然保留数据,不用重新传递。

步骤拆解:

  1. 创建共享ViewModel:里面用LiveData来保存选中的瓦片坐标
  2. 在Custom View里获取ViewModel并更新数据:选中瓦片时更新LiveData的值
  3. 在主Activity里观察LiveData:数据变化时自动触发WiFi扫描

ViewModel代码示例:

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import android.util.Pair;

public class GridTileViewModel extends ViewModel {
    // 用MutableLiveData保存选中的瓦片坐标,Pair用来存x和y
    private final MutableLiveData<Pair<Integer, Integer>> selectedTile = new MutableLiveData<>();

    // 更新选中的瓦片坐标
    public void updateSelectedTile(int x, int y) {
        selectedTile.setValue(new Pair<>(x, y));
    }

    // 给外部提供观察数据的入口
    public MutableLiveData<Pair<Integer, Integer>> getSelectedTile() {
        return selectedTile;
    }
}

Custom View代码示例:

public class GridDrawView extends View {
    private GridTileViewModel mViewModel;

    public GridDrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 从Activity获取ViewModel实例(注意Context必须是AppCompatActivity)
        if (context instanceof AppCompatActivity) {
            mViewModel = new ViewModelProvider((AppCompatActivity) context).get(GridTileViewModel.class);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            int selectedX = calculateTileX(event.getX());
            int selectedY = calculateTileY(event.getY());

            // 更新ViewModel里的LiveData
            if (mViewModel != null) {
                mViewModel.updateSelectedTile(selectedX, selectedY);
            }
        }
        return super.onTouchEvent(event);
    }

    // 你的坐标计算和绘制方法...
}

主Activity代码示例:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        GridTileViewModel viewModel = new ViewModelProvider(this).get(GridTileViewModel.class);
        // 观察LiveData,一旦坐标变化就触发WiFi扫描
        viewModel.getSelectedTile().observe(this, tile -> {
            if (tile != null) {
                startWifiScanWithTile(tile.first, tile.second);
            }
        });
    }

    private void startWifiScanWithTile(int tileX, int tileY) {
        // 你的WiFi扫描逻辑,和方案1里的一样
        Log.d("WiFi_Scan", "扫描关联瓦片: (" + tileX + ", " + tileY + ")");
    }
}

小建议

如果只是简单的“选中瓦片→触发扫描”逻辑,方案1的接口回调足够用了,代码少还直观;如果你的项目比较复杂,或者需要处理配置变化,那方案2的ViewModel会更省心。

内容的提问来源于stack exchange,提问作者Tommy Jackson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:50:10